# Pi-hole E-Paper Display
**A beautiful, professional dashboard for your Pi-hole stats on a Waveshare E-Paper display**
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://pi-hole.net/)

---
## Overview
This project displays real-time Pi-hole statistics on a Waveshare 2.7" E-Paper display with a clean, grid-based layout inspired by professional dashboard designs. Perfect for monitoring your network's ad-blocking performance at a glance.
### Features
- **6-Block Grid Layout** - Clean 3×2 design showing comprehensive metrics
- **Pi-hole Statistics** - Ads blocked, DNS queries, block percentage, and active devices
- **System Monitoring** - Real-time CPU usage and system uptime
- **Real-time Updates** - Auto-refreshes every 5 minutes (configurable)
- **Flexible Data Sources** - Supports both Pi-hole CLI and HTTP API
- **Smart Font Detection** - Automatically finds and uses the best available fonts
- **SSH Support** - Can fetch stats from remote Pi-hole instances
- **Preview Mode** - Test without physical display hardware
- **Customizable Branding** - Add your own title/name to the display
---
## Display Layout
The display uses a 6-block grid layout (3 columns × 2 rows) showing comprehensive statistics:
```
┌──────────────────────────────────────────────────────┐
│ ○ Your Network Name 2025-12-14 ● │
├─────────────────┬─────────────────┬──────────────────┤
│ │ │ │
│ 1,234 │ 12,345 │ 10.5% │
│ Blocked │ Queries │ Percent │
│ │ │ │
├─────────────────┼─────────────────┼──────────────────┤
│ │ │ │
│ 15 │ 12.3% │ 5d 12h │
│ Devices │ CPU │ Uptime │
│ │ │ │
└─────────────────┴─────────────────┴──────────────────┘
```
**Top Row:**
- **Blocked** - Total ads blocked today
- **Queries** - Total DNS queries today
- **Percent** - Percentage of queries blocked
**Bottom Row:**
- **Devices** - Number of active devices protected
- **CPU** - Current CPU usage percentage
- **Uptime** - System uptime (days/hours format)
---
## Requirements
### Hardware
- Raspberry Pi (or any Linux system with GPIO)
- Waveshare 2.7" E-Paper Display (Model: epd2in7b_V2)
- Pi-hole installed and running
---
## Prerequisites
### 1. Update and upgrade
```bash
sudo apt update && sudo apt upgrade
sudo reboot
```
### 2. Pi-hole installation
```bash
curl -sSL https://install.pi-hole.net | bash
sudo pihole -g
```
### 3. Enable SPI for e-paper display
```bash
sudo raspi-config
# Select --> Interfaces --> SPI --> enable
sudo reboot
```
### 4. Verify python3 and install dependencies
```bash
# Single line
sudo apt install -y python3-pip python3-pil python3-numpy python3-spidev python3-gpiozero python3-psutil
# Individual
sudo apt install python3-pip
sudo apt install python3-pil
sudo apt install python3-numpy
sudo apt install python3-spidev
sudo apt install python3-gpiozero
sudo apt install python3-psutil
```
---
## Installation
### 1. Clone or Download
```bash
git clone https://gitea.bingadventures.com/mbtech/epaper-pihole
cd epaper-pihole
```
### 2. Install Waveshare E-Paper Library
```bash
# Download the Waveshare library
# Clone with sparse checkout enabled
git clone --depth 1 --filter=blob:none --sparse \
https://github.com/waveshare/e-Paper.git
cd e-Paper
# Checkout only the waveshare_epd directory
git sparse-checkout set RaspberryPi_JetsonNano/python/lib/waveshare_epd
# Now copy just that directory into your project
# example:: cp -r RaspberryPi_JetsonNano/python/lib/waveshare_epd ~/epaper-pihole/
cp -r RaspberryPi_JetsonNano/python/lib/waveshare_epd # normally I install into the home directory
```
### 3. Update Configuration
Edit `epaper-pihole.py` and configure the following settings:
```python
# Choose your data source
USE_CLI = True # True = use pihole command, False = use HTTP API
# For SSH mode (remote Pi-hole)
USE_SSH = False
SSH_HOST = "user@"
# For HTTP API mode
PIHOLE_HOST = "" # Your Pi-hole IP address
PIHOLE_API_KEY = "" # Optional, for authenticated endpoints
# Display settings
REFRESH_INTERVAL = 300 # Seconds between updates (5 minutes)
# Paths
WAVESHARE_LIB_PATH = '/home//epaper-pihole/waveshare_epd' # Path to Waveshare library
PREVIEW_IMAGE_PATH = '/home//pihole_display.png' # Path for preview image output
# Branding
DISPLAY_TITLE = "Your Network Name" # Change to your name!
```
**Note:** All paths are now configurable in the configuration section. Update `WAVESHARE_LIB_PATH` and `PREVIEW_IMAGE_PATH` to match your system.
### 4. Run the Script
```bash
# Make executable
chmod +x epaper-pihole.py
# Run directly
python3 epaper-pihole.py
# Or run in background
nohup python3 epaper-pihole.py &
```
---
## Configuration Modes
### CLI Mode (Recommended)
Uses the `pihole` command-line tool directly. Requires `sudo` access.
**Pros:**
- More reliable
- No API key needed
- Works with all Pi-hole versions
**Setup:**
```python
USE_CLI = True
USE_SSH = False # Set True for remote Pi-hole
```
### HTTP API Mode
Uses Pi-hole's web API endpoint.
**Pros:**
- No sudo required
- Works remotely without SSH
**Setup:**
```python
USE_CLI = False
PIHOLE_HOST = ""
PIHOLE_API_KEY = "" # Get from Pi-hole settings
```
---
## Auto-Start on Boot
### Using systemd this works but if enabled than manual running of the script will fail
### Stop service then you can run manually again
Create a service file:
```bash
sudo nano /etc/systemd/system/pihole-display.service
```
Add the following:
```ini
[Unit]
Description=Pi-hole E-Paper Display
After=network.target
[Service]
Type=simple
User= ## make sure you have the correct user name
WorkingDirectory=/home//pihole-epaper ## Make sure proper directory
ExecStart=/usr/bin/python3 /home//pihole-epaper/epaper-pihole.py ## Again proper directory
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
Enable and start:
```bash
sudo systemctl enable pihole-display.service
sudo systemctl start pihole-display.service
sudo systemctl status pihole-display.service
```
---
## Preview Mode
Run without physical display hardware for testing:
```bash
python3 epaper-pihole.py
```
If the Waveshare library isn't detected, it automatically saves preview images to the path specified in `PREVIEW_IMAGE_PATH` (default: `/home/pi/pihole_display.png`).
---
## Troubleshooting
### Display Not Updating
- Check GPIO connections
- Verify Waveshare library installation
- Check display model matches (epd2in7b_V2)
### No Pi-hole Data
- **CLI Mode**: Ensure `sudo pihole` commands work
- **HTTP API Mode**: Verify Pi-hole host and API key
- **SSH Mode**: Test SSH connection manually
### Font Issues
The script auto-detects fonts in this priority:
1. DejaVu Sans
2. Liberation Sans
3. FreeSans
4. Default fallback
To install fonts:
```bash
sudo apt-get install fonts-dejavu fonts-liberation
```
### System Stats Not Showing
- **CPU shows 0% or N/A**: Install `psutil` for better CPU monitoring.
- **Uptime shows N/A**: Ensure `uptime` command is available on your system
- **Remote system via SSH**: Make sure SSH commands can execute without password (use SSH keys)
---
## Customization
### Change Refresh Interval
```python
REFRESH_INTERVAL = 600 # 10 minutes
```
### Modify Display Title
```python
DISPLAY_TITLE = "My Network Shield"
```
### Update Paths
```python
WAVESHARE_LIB_PATH = '/custom/path/to/waveshare_epd'
PREVIEW_IMAGE_PATH = '/custom/path/to/preview.png'
```
### Adjust Font Sizes
In the `create_display_image()` function (around line 200):
```python
font_title = ImageFont.truetype(fonts['bold'], 20) # Header
font_huge = ImageFont.truetype(fonts['bold'], 32) # Main numbers
font_large = ImageFont.truetype(fonts['bold'], 24) # Secondary numbers
font_small = ImageFont.truetype(fonts['regular'], 12) # Labels
```
---
## Code Quality
The code has been optimized with the following improvements:
- ✅ **6-block layout** - Displays 6 metrics in a clean 3×2 grid (Pi-hole + system stats)
- ✅ **System monitoring** - CPU usage and uptime tracking with fallback methods
- ✅ **Configurable paths** - All file paths are now in the configuration section
- ✅ **Comprehensive comments** - Well-documented code with clear explanations
- ✅ **Proper exception handling** - Specific exception types instead of bare except clauses
- ✅ **Clean code** - Removed commented-out code and unused lines
- ✅ **Main execution** - Proper `if __name__ == "__main__"` block with `main()` call
---
## Console Output
When running, you'll see output like:
```text
Pi-hole E-Paper Display - Binglab Style (6-Block Layout)
============================================================
Fetching Pi-hole stats...
Fetching system stats...
Queries: 12,345
Blocked: 1,234 (10.52%)
Devices: 15
CPU: 12.3%
Uptime: 5d 12h
Using fonts: DejaVuSans-Bold.ttf, DejaVuSans.ttf
Updating display...
✓ Display updated
Next update in 300 seconds...
```
---
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
---
## License
This project is open source. Feel free to use and modify as needed.
---
## Credits
- **Waveshare** - E-Paper display hardware and libraries
- **Pi-hole** - Network-wide ad blocking
- **Binglab** - Design inspiration
---
## Support
For issues and questions:
- Check the troubleshooting section
- Review Pi-hole documentation
- Check Waveshare E-Paper documentation
---
**Made with ☕ for a cleaner internet**
[Pi-hole](https://pi-hole.net/) | [Waveshare](https://www.waveshare.com/) | [Python](https://www.python.org/)