おさらい
import asyncio
import os
import nextcord
from dotenv import load_dotenv
from nextcord.ext import commands
load_dotenv()
bot = commands.Bot()
@bot.slash_command()
async def git(interaction: nextcord.Interaction):
pass
@git.subcommand()
async def status(interaction: nextcord.Interaction):
process = await asyncio.create_subprocess_shell("git status", stdout=asyncio.subprocess.PIPE)
stdout, stderr = await process.communicate()
await interaction.response.send_message(embed=nextcord.Embed(
title="Git Status Result",
description=f"```sh\n{stdout.decode('utf-8')}```"
))
if __name__ == "__main__":
token = os.getenv("BOT_TOKEN")
if token is None:
print("TOKENが設定されていません。")
else:
bot.run(token)
仕上げにArduinoCLIをガッチャンコ...
Remember me?
ArduinoCLIのコマンドの構造は覚えていますでしょうか。
今回はコンパイルコマンドを使用して、コンパイル結果を送信するような構造を作っていきましょう。
まずは、Arduinoコマンドグループを作成します。
...
@bot.slash_command()
async def arduino(interaction: nextcord.Interaction):
pass
...
次に、コンパイルコマンドを作成します。
ArduinoCLIのコンパイルコマンド
...
@arduino.subcommand()
async def compile(interaction: nextcord.Interaction):
process = await asyncio.create_subprocess_shell("arduino-cli compile", stdout=asyncio.subprocess.PIPE)
stdout, stderr = await process.communicate()
await interaction.response.send_message(embed=nextcord.Embed(
title="Arduino Compile Result",
description=f"```sh\n{stdout.decode('utf-8')}```",
color=0x008184
))
...
さて、ここで問題があります。
FQBNやプロジェクトのパスを指定しないとコンパイルできないのですが、これをどうやって指定するかです。
FQBN・プロジェクトを指定できるようにする
...
@arduino.subcommand()
- async def compile(interaction: nextcord.Interaction):
- process = await asyncio.create_subprocess_shell("arduino-cli compile", stdout=asyncio.subprocess.PIPE)
+ async def compile(interaction: nextcord.Interaction, project: str, fqbn: str = "esp32:esp32:esp32"):
+ process = await asyncio.create_subprocess_shell(f"arduino-cli compile -b {fqbn} {project}", stdout=asyncio.subprocess.PIPE)
stdout, stderr = await process.communicate()
await interaction.response.send_message(embed=nextcord.Embed(
title="Arduino Compile Result",
description=f"```sh\n{stdout.decode('utf-8')}```",
color=0x008184
))
...
これで、FQBN及びプロジェクトを指定してコマンドを実行(指定しない場合はデフォルトのesp32:esp32:esp32
でコマンドを実行)することができるようになりました。
※このコマンドには明らかな脆弱性(文字列をそのまんまコマンドラインに流している)があるので、実際に使うときはスラッシュコマンドの実行権限設定をちゃんとするか、エスケープなどの処理を行ってください。
あとちょっと!
...
@arduino.subcommand()
async def compile(interaction: nextcord.Interaction, project: str, fqbn: str = "esp32:esp32:esp32"):
process = await asyncio.create_subprocess_shell(f"arduino-cli compile -b {fqbn} {project}", stdout=asyncio.subprocess.PIPE)
+ await interaction.response.defer()
stdout, stderr = await process.communicate()
- await interaction.response.send_message(embed=nextcord.Embed(
+ await interaction.send(embed=nextcord.Embed(
title="Arduino Compile Result",
description=f"```sh\n{stdout.decode('utf-8')}```",
color=0x008184
))
...
-
interaction.response.defer()
を追加
これは、本来であれば3秒ぐらい以内にメッセージを返信しなければエラーになってしまうのですが、このコマンドはコンパイルに時間がかかるため、5秒以内にメッセージを返信することができません。
そこで、このdefer()
を使用すると、猶予時間が3秒から15分ぐらいに伸びます。
これで、コンパイルが終わるまで待つことができます。 -
interaction.response.send_message
をinteraction.send
に変更
これは、interaction.response.send_message
は、interaction.response.defer()
を使用している場合に使用するメソッドで、interaction.send
は、interaction.response.defer()
を使用していない場合に使用するメソッドです。
今回はinteraction.response.defer()
を使用しているので、interaction.response.send_message
ではなくinteraction.send
を使用する必要があります。
ほんとに最後!
...
@arduino.subcommand()
async def compile(interaction: nextcord.Interaction, project: str, fqbn: str = "esp32:esp32:esp32"):
process = await asyncio.create_subprocess_shell(f"arduino-cli compile -b {fqbn} {project}", stdout=asyncio.subprocess.PIPE)
await interaction.response.defer()
stdout, stderr = await process.communicate()
+ project_name = project.split("/")[-1]
+ fqbn_path = fqbn.replace(":", ".")
+ file_name = f"{project_name}.ino.{'bin' if fqbn_path.startswith('esp32') else 'zip'}"
+ file_path = f"{project}/build/{fqbn_path}/{file_name}"
await interaction.send(embed=nextcord.Embed(
title="Arduino Compile Result",
description=f"```sh\n{stdout.decode('utf-8')}```",
color=0x008184
- ))
+ ), file=nextcord.File(file_path, filename=file_name))
...
これで、コンパイル結果をファイルとして送信することができるようになりました。
あとは、ダウンロードしたファイルをマイコンに書き込むだけです。これにて終わり!
まとめ...ない!
残り時間は29時間。
というわけで、「DiscordBOTでも作ってみない?」