-
Notifications
You must be signed in to change notification settings - Fork 1
Feature/hardware integration #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
2c3015a
c53a625
0d29fa8
a45d410
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import os | ||
| import asyncio | ||
| import discord | ||
| from discord import app_commands | ||
| from dotenv import load_dotenv | ||
| import serial | ||
| import time | ||
|
|
||
| # 1. Load configuration from .env file | ||
| load_dotenv() | ||
| TOKEN = os.getenv('DISCORD_TOKEN') | ||
| SERIAL_PORT = os.getenv('SERIAL_PORT', 'COM5') | ||
| ALLOWED_CHANNEL_ID = os.getenv('ALLOWED_CHANNEL_ID') # NEW: Re-load from .env | ||
|
|
||
| # 2. Setup Serial Connection | ||
| try: | ||
| arduino = serial.Serial(SERIAL_PORT, 9600, timeout=1) | ||
| time.sleep(2) | ||
| print(f"✅ Connected to Arduino on {SERIAL_PORT}!") | ||
| except Exception as e: | ||
| print(f"❌ Hardware Error on {SERIAL_PORT}: {e}") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming you don't do the above... do note that since you are handling the error, your script continues executing from here... but when you go call Consider either setting |
||
|
|
||
| # 3. Discord Bot Logic | ||
| class HardwareBot(discord.Client): | ||
| def __init__(self): | ||
| super().__init__(intents=discord.Intents.default()) | ||
| self.tree = app_commands.CommandTree(self) | ||
|
|
||
| async def setup_hook(self): | ||
| await self.tree.sync() | ||
|
|
||
| client = HardwareBot() | ||
|
|
||
| # --- COMMANDS WITH COOLDOWNS --- | ||
|
|
||
| @client.tree.command(name="wave", description="Send a long wave blink") | ||
| @app_commands.checks.cooldown(1, 10.0, key=lambda i: i.user.id) # 1 use every 10s | ||
| async def wave(interaction: discord.Interaction): | ||
| if ALLOWED_CHANNEL_ID and str(interaction.channel.id) != str(ALLOWED_CHANNEL_ID): | ||
| await interaction.response.send_message("❌ This command is not allowed in this channel.", ephemeral=True) | ||
| return | ||
| arduino.write(b'W') | ||
| await interaction.response.send_message(f"👋 {interaction.user.display_name} sent a wave!") | ||
|
|
||
| @client.tree.command(name="love", description="Send fast blinks of love") | ||
| @app_commands.checks.cooldown(1, 10.0, key=lambda i: i.user.id) # 1 use every 10s | ||
| async def love(interaction: discord.Interaction): | ||
| if ALLOWED_CHANNEL_ID and str(interaction.channel.id) != str(ALLOWED_CHANNEL_ID): | ||
| await interaction.response.send_message("❌ This command is not allowed in this channel.", ephemeral=True) | ||
| return | ||
| arduino.write(b'L') | ||
| await interaction.response.send_message(f"❤️ {interaction.user.display_name} is sending love!") | ||
|
|
||
| @client.tree.command(name="question", description="Send a pulse for a question") | ||
| @app_commands.checks.cooldown(1, 10.0, key=lambda i: i.user.id) | ||
| async def question(interaction: discord.Interaction): | ||
| if ALLOWED_CHANNEL_ID and str(interaction.channel.id) != str(ALLOWED_CHANNEL_ID): | ||
| await interaction.response.send_message("❌ This command is not allowed in this channel.", ephemeral=True) | ||
| return | ||
| arduino.write(b'Q') | ||
| await interaction.response.send_message(f"❓ {interaction.user.display_name} has a question!") | ||
|
|
||
| # --- GLOBAL ERROR HANDLER --- | ||
| # This one function handles the "Rate Limit" message for ALL commands above | ||
| @client.tree.error | ||
| async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError): | ||
| if isinstance(error, app_commands.CommandOnCooldown): | ||
| await interaction.response.send_message( | ||
| f"⏳ Slow down, {interaction.user.display_name}! Try again in {error.retry_after:.1f}s.", | ||
| ephemeral=True # Only the spammer sees this | ||
| ) | ||
| else: | ||
| # Log other errors so you can see them in your terminal | ||
| print(f"Command Error: {error}") | ||
|
|
||
| def main(): | ||
| # 4. Run the Bot using the hidden Token | ||
| if TOKEN: | ||
| client.run(TOKEN) | ||
| else: | ||
| print("❌ Error: No token found. Did you create the .env file?") | ||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels weird to have this at the module global scope, where it is executed once, on import (and before anything starts up). Is this the right place for this, or should it be tucked into a function or method somewhere?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One pattern you could use is a global variable and a function return or init.
The benefit here is that the
arduinoinstance isn't created until the first time it's called for, and then it is cached in the global scope. For each successive request, the cached copy is returned.Lines like 42, 51 and 60 would need to change from: