A Python bot that uses Discord to control GPIO pins on a Raspberry Pi Zero W. The bot only responds to messages from a specific Discord channel.
- Control GPIO pins remotely via Discord
- Only responds to messages from a specified Discord channel
- Command-based interface to control devices
- Timed operations (e.g., turn on a device for 1 hour)
- Automatic scheduling: Set devices to turn on/off at specific times
- Emulation mode for testing on non-RPi devices
- Configurable device-to-pin mapping via .env file
- Reasonable unit test coverage
- Python 3.11+
- Raspberry Pi Zero W (or any Raspberry Pi)
- Discord bot token
- Discord server with a channel for the bot
- Clone this repository:
git clone https://github.com/fclaude/waterbot.git
cd waterbot- Install the required packages:
pip install -r requirements.txt- Create a
.envfile with your configuration:
# Discord Configuration
DISCORD_BOT_TOKEN="your_discord_bot_token_here"
DISCORD_CHANNEL_ID="123456789012345678"
# OpenAI Configuration
OPENAI_API_KEY="your_openai_api_key_here" # pragma: allowlist secret
OPENAI_MODEL="gpt-4o-mini"
# Operation Mode (rpi or emulation)
OPERATION_MODE=rpi
# Device to GPIO Pin Mapping
# Format: DEVICE_NAME=GPIO_PIN_NUMBER
DEVICE_LIGHT=17
DEVICE_FAN=18
DEVICE_PUMP=27
DEVICE_HEATER=22
# Default timeout in seconds (optional, for timed operations)
DEFAULT_TIMEOUT=3600
# Scheduling Configuration
# Enable automatic scheduling of devices
ENABLE_SCHEDULING=true
# JSON file to store schedule configuration (optional)
SCHEDULE_CONFIG_FILE=schedules.json
# Schedule Configuration (alternative to JSON file)
# Format: SCHEDULE_<DEVICE>_<ACTION>=HH:MM[,HH:MM,...]
# Examples:
# SCHEDULE_PUMP_ON=08:00,20:00
# SCHEDULE_PUMP_OFF=12:00,23:00
# SCHEDULE_LIGHT_ON=06:30
# SCHEDULE_LIGHT_OFF=22:00This bot uses Discord's bot API to communicate. Follow these steps to set up your Discord bot:
- Create a Discord Application at the Discord Developer Portal
- Create a bot user in your application
- Copy the bot token and add it to your
.envfile asDISCORD_BOT_TOKEN - Invite the bot to your Discord server with appropriate permissions:
- Send Messages
- Read Message History
- Use Slash Commands
- Get your Discord channel ID (enable Developer Mode in Discord, right-click channel, Copy ID)
- Update your
.envfile with the channel ID
python -m waterbot.botSend these commands from the Discord channel to control your devices:
status- Show the status of all deviceson <device>- Turn on a specific deviceoff <device>- Turn off a specific deviceon <device> <seconds>- Turn on a device for a specified timeoff <device> <seconds>- Turn off a device for a specified timeon all- Turn on all devicesoff all- Turn off all devices
schedules- Show all configured schedules and next runsschedule <device> <on|off> <HH:MM>- Add a new scheduleunschedule <device> <on|off> <HH:MM>- Remove a schedule
- Send any unrecognized command to get help
status
on light
off pump
on fan 3600
off heater 1800
on all
off all
# Show all schedules
schedules
# Turn on pump at 8:00 AM and 8:00 PM every day
schedule pump on 08:00
schedule pump on 20:00
# Turn off pump at 12:00 PM and 11:00 PM every day
schedule pump off 12:00
schedule pump off 23:00
# Turn on lights at 6:30 AM
schedule light on 06:30
# Turn off lights at 10:00 PM
schedule light off 22:00
# Remove a schedule
unschedule pump on 20:00
For development and testing on non-RPi devices, set
OPERATION_MODE=emulation in your .env file. In this mode, GPIO
operations will be simulated and printed to the console.
The project includes comprehensive unit tests. To run the tests:
# Install test dependencies
pip install -r requirements.txt
# Run all tests
pytest
# Run tests with coverage report
pytest --cov=waterbot --cov-report=html
# Run specific test file
pytest tests/test_gpio_handler.py
# Run tests matching a pattern
pytest -k "test_device"The test suite covers:
- GPIO interface and hardware abstraction
- Device control logic and timing
- Schedule configuration and management
- Discord bot message handling
- Command parsing and validation
- Error handling and edge cases
Tests use mock objects and dependency injection to ensure they can run without hardware dependencies or external services.
WaterBot includes comprehensive CI/CD pipelines for automated testing and deployment:
- Automated testing on every commit and merge request
- Multi-Python version testing (3.8-3.11)
- Code quality checks (linting, formatting, type checking)
- Security vulnerability scanning
- Docker image building and testing
- Similar comprehensive pipeline for GitHub repositories
- Automatic PyPI publishing on releases
- Codecov integration for coverage reporting
See CI-CD.md for detailed pipeline documentation.
To run the bot as a systemd service on your Raspberry Pi, follow these comprehensive steps:
- Ensure you have a dedicated user for the service (recommended for security):
# Create a dedicated user for the bot (optional but recommended)
sudo useradd -r -s /bin/false -d /opt/waterbot waterbot-service
# Or use the default 'pi' user if you prefer- Add the service user to the gpio group (for GPIO access):
# If using dedicated user:
sudo usermod -a -G gpio waterbot-service
# If using pi user:
sudo usermod -a -G gpio pi- Install the bot in a system location (recommended):
# Create application directory
sudo mkdir -p /opt/waterbot
sudo chown $USER:$USER /opt/waterbot
# Clone and setup the application
cd /opt/waterbot
git clone https://github.com/fclaude/waterbot.git .- Install Python dependencies:
# Install system-wide or in a virtual environment
sudo pip3 install -r requirements.txt
# Or create a virtual environment (recommended):
python3 -m venv /opt/waterbot/venv
sudo chown -R waterbot-service:waterbot-service /opt/waterbot
source /opt/waterbot/venv/bin/activate
pip install -r requirements.txt- Setup configuration:
# Create and configure the .env file
sudo cp .env.example .env # if you have an example file
sudo nano /opt/waterbot/.env
# Ensure proper ownership
sudo chown waterbot-service:waterbot-service /opt/waterbot/.env
sudo chmod 600 /opt/waterbot/.env # Secure the config file- Configure Discord bot credentials for the service user:
# Ensure the .env file contains proper Discord configuration
# DISCORD_BOT_TOKEN and DISCORD_CHANNEL_ID should be set
# The service user should have read access to this file- Create the systemd service file:
sudo nano /etc/systemd/system/waterbot.service- Add the service configuration:
[Unit]
Description=WaterBot Discord GPIO Controller
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=waterbot-service
Group=waterbot-service
WorkingDirectory=/opt/waterbot
Environment=PATH=/opt/waterbot/venv/bin:/usr/local/bin:/usr/bin:/bin
# Use virtual environment if created
ExecStart=/opt/waterbot/venv/bin/python -m waterbot.bot
# Or use system Python
# ExecStart=/usr/bin/python3 -m waterbot.bot
# Restart configuration
Restart=always
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/waterbot
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=waterbot
[Install]
WantedBy=multi-user.targetNote: If using the pi user instead of a dedicated user, change User=pi
and Group=pi in the service file, and adjust paths accordingly (e.g.,
/home/pi/waterbot).
- Reload systemd and enable the service:
sudo systemctl daemon-reload
sudo systemctl enable waterbot.service- Start the service:
sudo systemctl start waterbot.service- Check service status:
sudo systemctl status waterbot.service- View service logs:
# View recent logs
sudo journalctl -u waterbot.service -f
# View logs from specific time
sudo journalctl -u waterbot.service --since "1 hour ago"
# View all logs for the service
sudo journalctl -u waterbot.service --no-pagerCommon issues and solutions:
-
Permission denied errors:
- Ensure the service user is in the
gpiogroup - Check file ownership and permissions for the bot directory
- Verify the .env file is accessible to the service user
- Ensure the service user is in the
-
Discord bot not working:
- Ensure the Discord bot token is valid and properly configured
- Check that the bot has permissions in the Discord channel
- Verify the Discord channel ID is correct
-
Module import errors:
- Ensure all dependencies are installed in the correct Python environment
- Check that the PYTHONPATH includes the waterbot directory
- Verify the virtual environment path (if used) is correct
-
Service won't start:
- Check the service logs:
sudo journalctl -u waterbot.service - Verify all file paths in the service configuration
- Test the bot manually first:
python3 -m waterbot.bot
- Check the service logs:
-
GPIO access issues:
- Ensure the service user is in the
gpiogroup:groups waterbot-service - Check that GPIO pins are not being used by other processes
- Verify the device-to-pin mapping in your .env file
- Ensure the service user is in the
# Start the service
sudo systemctl start waterbot.service
# Stop the service
sudo systemctl stop waterbot.service
# Restart the service
sudo systemctl restart waterbot.service
# Enable service to start on boot
sudo systemctl enable waterbot.service
# Disable service from starting on boot
sudo systemctl disable waterbot.service
# Check if service is running
sudo systemctl is-active waterbot.service
# View service configuration
sudo systemctl show waterbot.service