I’m working on a new controller for my mushroom tent, and went with a raspberry pi5 and a Pi-Plates RELAYplate to control the fan, humidifier, lights, pumps, etc. Little did I know how much of a headache the changes to how the pi5 handles the GPIO would be. After struggling for a bit trying to figure out how to get a custom mutli-channel output working, I turned to claude.ai, and after trying several methods finally found one that worked. I’ve attached the documentation and code, in case someone else runs into something similar. The issue was the system-site-packages are not included in the stock Mycodo environment, so another one is created and used to control the RELAYplate.
Caveats
- This was just for fun. Using the existing outputs for relays still works great, and I had been using that.
- I’m not super fluent in python, and the code was generated. Use at your own risk
- It’s been working for a whole 3 hours at the time of this post.
Also, the footprint of the RELAYplate matches the pi-plates CM4 carrier, not a standard pi. It fits, but does hang over the sides a bit. I recommend some kapton or electrical tape over the USB shell of the pi if you’re mounting it like a hat.
Generated Documentation:
Hardware Prerequisites
Before setting up the software integration, ensure:
- Hardware Installation:
- Pi-Plates RELAYplate is properly connected to the Raspberry Pi GPIO header
- Power is connected to the Pi-Plates board if required
- Jumpers are set correctly for the desired board address (default is 0)
- System Configuration:
bash
# Enable SPI interface (required for Pi-Plates)
sudo raspi-config
# Navigate to: Interface Options > SPI > Enable > Yes > Finish
# Alternatively, enable SPI from command line
sudo raspi-config nonint do_spi 0
# Reboot to apply changes
sudo reboot
# Verify SPI is enabled
ls -la /dev/spidev*
# Should show devices like /dev/spidev0.0 and /dev/spidev0.1
# Install required system packages
sudo apt-get update
sudo apt-get install -y python3-venv python3-dev python3-pip
sudo apt-get install -y python3-gpiod gpiod
- User Permissions:
bash
# Add user to required groups
sudo usermod -a -G gpio,spi root
# Set permissions for GPIO and SPI devices
sudo chmod 660 /dev/gpiochip*
sudo chmod 660 /dev/spidev*
# Create udev rules for persistent permissions (optional)
echo 'SUBSYSTEM=="gpio", KERNEL=="gpiochip*", GROUP="gpio", MODE="0660"' | sudo tee /etc/udev/rules.d/99-gpio.rules
echo 'SUBSYSTEM=="spidev", KERNEL=="spidev*", GROUP="spi", MODE="0660"' | sudo tee /etc/udev/rules.d/99-spi.rules
# Reload udev rules
sudo udevadm control --reload-rules
sudo udevadm trigger
```# Pi-Plates Integration with Mycodo
This document provides comprehensive documentation for the integration of Pi-Plates RELAYplate hardware with the Mycodo environmental monitoring and control system.
Overview
The integration allows Mycodo to control Pi-Plates RELAYplate boards through a bridge script that leverages an existing Pi-Plates virtual environment where the library is properly configured and working.
File Structure
/opt/
├── Mycodo/ # Main Mycodo installation
│ ├── env/ # Mycodo virtual environment
│ │ └── ...
│ └── mycodo/
│ ├── user_python_code/ # Contains Mycodo Python Code outputs
│ │ └── output_*.py # Python code for output modules
│ └── ...
└── python_scripts_env/ # Virtual environment for Pi-Plates
├── bin/
│ └── python # Python interpreter
├── lib/
│ └── python3.11/
│ └── site-packages/
│ └── piplates/ # Pi-Plates library
├── relay_bridge.py # Bridge script for Pi-Plates control
└── relay_bridge.py.bak # Backup of the bridge script (optional)
Virtual Environments
Two virtual environments are involved in this integration:
- Mycodo Virtual Environment
- Path:
/opt/Mycodo/env/
- Python Version: 3.11.2
- Purpose: Runs the Mycodo application but cannot directly access Pi-Plates hardware due to GPIO access issues
- Pi-Plates Virtual Environment
- Path:
/opt/python_scripts_env/
- Python Version: 3.11.2
- Configuration: Created with
--system-site-packages
flag - Purpose: Contains the working Pi-Plates library with proper hardware access and the bridge script
- Note: This environment is critical for the integration as it has working GPIO and SPI access
Scripts
Pi-Plates Bridge Script
Location: /opt/python_scripts_env/relay_bridge.py
Purpose: Acts as a bridge between Mycodo and the Pi-Plates hardware by executing commands through the Pi-Plates virtual environment where the library works correctly.
Implementation Details:
- Located within the Pi-Plates virtual environment directory
- Uses the virtual environment’s Python interpreter to access the Pi-Plates library
- Provides a consistent JSON-based API for Mycodo to interact with
- Handles errors and returns standardized responses
Script Content:
python
#!/usr/bin/env python3
"""
Bridge script to control pi-plates RELAY boards.
This script runs directly in the Pi-Plates virtual environment.
"""
import sys
import json
import piplates.RELAYplate as RELAY
def handle_command(address, command, *args):
"""Handle relay commands"""
try:
# Force initialize the relaysPresent array
RELAY.relaysPresent = [0] * 8
RELAY.relaysPresent[address] = 1
if command == "on" and len(args) > 0:
relay_num = int(args[0])
RELAY.relayON(address, relay_num)
return {"status": "success", "message": f"Relay {relay_num} turned ON"}
elif command == "off" and len(args) > 0:
relay_num = int(args[0])
RELAY.relayOFF(address, relay_num)
return {"status": "success", "message": f"Relay {relay_num} turned OFF"}
elif command == "state":
state = RELAY.relaySTATE(address)
return {"status": "success", "state": state}
else:
return {"status": "error", "message": f"Unknown command: {command}"}
except Exception as e:
return {"status": "error", "message": str(e)}
if __name__ == "__main__":
if len(sys.argv) < 3:
print(json.dumps({"status": "error", "message": "Usage: relay_bridge.py [address] [command] [args...]"}))
sys.exit(1)
try:
address = int(sys.argv[1])
command = sys.argv[2]
args = sys.argv[3:]
result = handle_command(address, command, *args)
print(json.dumps(result))
except Exception as e:
print(json.dumps({"status": "error", "message": str(e)}))
Usage:
bash
# Turn on relay 3 at address 0
/opt/python_scripts_env/relay_bridge.py 0 on 3
# Turn off relay 3 at address 0
/opt/python_scripts_env/relay_bridge.py 0 off 3
# Get state of all relays at address 0
/opt/python_scripts_env/relay_bridge.py 0 state
Mycodo Python Code Output
Location: In Mycodo’s database, accessible via the web interface under Setup → Output → On/Off: Python Code
Purpose: Provides the interface between Mycodo’s output system and the bridge script
On Code:
python
# Import modules at the top level
import subprocess
import json
# Run the relay_bridge.py script to turn on relay 3 at address 0
try:
result = subprocess.run(
['/opt/python_scripts_env/relay_bridge.py', '0', 'on', '3'],
capture_output=True,
text=True,
check=False
)
if result.returncode != 0:
self.logger.error(f"Command failed: {result.stderr}")
return False
response = json.loads(result.stdout)
if response['status'] == 'success':
return True
self.logger.error(f"Error turning relay on: {response.get('message', 'Unknown error')}")
return False
except Exception as e:
self.logger.error(f"Exception turning relay on: {str(e)}")
return False
Off Code:
python
# Import modules at the top level
import subprocess
import json
# Run the relay_bridge.py script to turn off relay 3 at address 0
try:
result = subprocess.run(
['/opt/python_scripts_env/relay_bridge.py', '0', 'off', '3'],
capture_output=True,
text=True,
check=False
)
if result.returncode != 0:
self.logger.error(f"Command failed: {result.stderr}")
return False
response = json.loads(result.stdout)
if response['status'] == 'success':
return True
self.logger.error(f"Error turning relay off: {response.get('message', 'Unknown error')}")
return False
except Exception as e:
self.logger.error(f"Exception turning relay off: {str(e)}")
return False
Hardware Configuration
- Hardware: Pi-Plates RELAYplate
- Address: 0 (configurable via jumpers on the board)
- Relays: 1-7 available, relay 3 used in example
- SPI Interface: Pi-Plates uses SPI for communication
- GPIO Access: Managed through the Pi-Plates virtual environment
Setup Process
- Create and Configure the Virtual Environment for Pi-Plates:
bash
# Create the directory for the virtual environment
sudo mkdir -p /opt/python_scripts_env
# Create the virtual environment with system packages
sudo python3 -m venv --system-site-packages /opt/python_scripts_env
# Set proper permissions
sudo chown -R root:root /opt/python_scripts_env
sudo chmod -R 755 /opt/python_scripts_env
# Activate the environment
source /opt/python_scripts_env/bin/activate
# Install pi-plates and all required dependencies in a single command
pip install pi-plates six spidev gpiod
# Verify installations
pip list | grep -E 'pi-plates|six|spidev|gpiod'
# Deactivate when done
deactivate
- Create the Bridge Script within the Virtual Environment:
bash
# Create the script file
sudo nano /opt/python_scripts_env/relay_bridge.py
# Paste the bridge script content
# (Copy and paste the script content from the documentation)
# Make the script executable
sudo chmod +x /opt/python_scripts_env/relay_bridge.py
# Test the script
/opt/python_scripts_env/relay_bridge.py 0 state
- Create Backup (optional):
bash
sudo cp /opt/python_scripts_env/relay_bridge.py /opt/python_scripts_env/relay_bridge.py.bak
- Configure Mycodo Outputs:
- Access Mycodo web interface
- Go to Setup → Output
- Click Add Output
- Select “On/Off: Python Code” from the dropdown
- Configure with appropriate On/Off code as documented above
- Save the output
Troubleshooting
Common Issues
- Permission Errors:
- Ensure bridge script is executable:
sudo chmod +x /opt/python_scripts_env/relay_bridge.py
- Check permissions for virtual environment:
ls -la /opt/python_scripts_env/bin/python
- Path Errors:
- Ensure Mycodo can find the bridge script: Use absolute path
/opt/python_scripts_env/relay_bridge.py
in Python code
- SPI Issues:
- Check if SPI is enabled:
ls -la /dev/spidev*
- Enable SPI if needed:
sudo raspi-config
→ Interfacing Options → SPI → Enable
- Virtual Environment Issues:
- Ensure pi-plates is installed in the environment:
sudo /opt/python_scripts_env/bin/pip list | grep pi-plates
- Try reinstalling if needed:
sudo /opt/python_scripts_env/bin/pip install --force-reinstall pi-plates
Debugging
To debug issues, add print
statements to the bridge script or use logging:
python
# Add to bridge script for debugging
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='/var/log/python_scripts.log',
filemode='a'
)
logger = logging.getLogger('python_scripts')
Then check the log:
bash
sudo tail -f /var/log/python_scripts.log
Extending the Integration
Adding More Relays
To control additional relays, create new outputs in Mycodo with modified relay numbers:
python
# Example for relay 4 instead of relay 3
subprocess.run(['/opt/python_scripts_env/relay_bridge.py', '0', 'on', '4'], ...)
Adding ADC Functionality
To add analog input functionality, extend the bridge script:
- Add ADC handler to
handle_command
function:
python
elif command == "adc" and len(args) > 0:
channel = int(args[0])
value = RELAY.getADC(address, channel)
return {"status": "success", "value": value}
- Create a Command Input in Mycodo to read the ADC value:
- Go to Setup → Input
- Add a new “Linux Command” input
- Configure the command:
/opt/python_scripts_env/relay_bridge.py 0 adc 0
Maintenance
Backup Strategy
Periodically back up the bridge script:
bash
sudo cp /opt/python_scripts_env/relay_bridge.py /opt/python_scripts_env/relay_bridge.py.bak
Updates
When updating Mycodo, verify the integration still works by:
- Testing the bridge script directly from command line
- Testing the output functionality in Mycodo web interface
Conclusion
This integration provides a robust solution for controlling Pi-Plates RELAYplate hardware from Mycodo by leveraging a dedicated virtual environment at /opt/python_scripts_env/
. This environment is configured with system-site-packages access to ensure proper GPIO and SPI functionality required for communicating with the Pi-Plates hardware.
The bridge script approach ensures compatibility even if Mycodo’s virtual environment changes in the future, as it delegates all hardware communication to the dedicated Pi-Plates environment.
^Claude’s words, not mine.