Skip to content

pi-hole / bookworm / st7789 changes #3049

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

Merged
merged 7 commits into from
Jun 4, 2025
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 55 additions & 57 deletions Pi_Hole_Ad_Blocker/mini_pitft_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
from PIL import Image, ImageDraw, ImageFont
import adafruit_rgb_display.st7789 as st7789

API_TOKEN = "YOUR_API_TOKEN_HERE"
api_url = "http://localhost/admin/api.php?summaryRaw&auth="+API_TOKEN
API_URL = "http://pi.hole/api/stats/summary"

# Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4):
cs_pin = digitalio.DigitalInOut(board.CE0)
cs_pin = digitalio.DigitalInOut(board.D17)
dc_pin = digitalio.DigitalInOut(board.D25)
reset_pin = None

Expand All @@ -34,77 +33,70 @@
spi = board.SPI()

# Create the ST7789 display:
disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE,
width=135, height=240, x_offset=53, y_offset=40)
disp = st7789.ST7789(
spi,
dc_pin,
cs_pin,
reset_pin,
135,
240,
baudrate=BAUDRATE,
x_offset=53,
y_offset=40,
rotation=90
)

# Create blank image for drawing.
# Make sure to create image with mode 'RGB' for full color.
height = disp.width # we swap height/width to rotate it to landscape!
width = disp.height
image = Image.new('RGB', (width, height))
rotation = 90

# Get drawing object to draw on image.
CANVAS_WIDTH = disp.height
CANVAS_HEIGHT = disp.width
image = Image.new('RGB', (CANVAS_WIDTH, CANVAS_HEIGHT))
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))
disp.image(image, rotation)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0


# Alternatively load a TTF font. Make sure the .ttf font file is in the
# same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24)

# Turn on the backlight
backlight = digitalio.DigitalInOut(board.D22)
backlight.switch_to_output()
backlight.value = True

# Add buttons as inputs
# Load default font (or replace with a TTF if desired)
FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
font = ImageFont.truetype(FONT_PATH, 20)

buttonA = digitalio.DigitalInOut(board.D23)
buttonA.switch_to_input()

while True:
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)
draw.rectangle((0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), outline=0, fill=(0, 0, 0))

# Shell scripts for system monitoring from here:
# https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load
cmd = "hostname -I | cut -d\' \' -f1"
IP = "IP: "+subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "hostname | tr -d \'\\n\'"
cmd = "hostname -I | cut -d' ' -f1"
IP = "IP: " + subprocess.check_output(cmd, shell=True).decode("utf-8").strip()
cmd = "hostname | tr -d '\\n'"
HOST = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'"
CPU = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB %.2f%%\", $3,$2,$3*100/$2 }'"
MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%d GB %s\", $3,$2,$5}'"
Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk \'{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}\'" # pylint: disable=line-too-long
cmd = (
"cat /sys/class/thermal/thermal_zone0/temp | "
"awk '{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}'"
)
Temp = subprocess.check_output(cmd, shell=True).decode("utf-8")


# Pi Hole data!
try:
r = requests.get(api_url)
data = json.loads(r.text)
DNSQUERIES = data['dns_queries_today']
ADSBLOCKED = data['ads_blocked_today']
CLIENTS = data['unique_clients']
except KeyError:
time.sleep(1)
continue

y = top
r = requests.get(API_URL, timeout=5)
r.raise_for_status()
data = r.json()
DNSQUERIES = data["queries"]["total"]
ADSBLOCKED = data["queries"]["blocked"]
CLIENTS = data["clients"]["total"]
except (KeyError, requests.RequestException, json.JSONDecodeError):
DNSQUERIES = None
ADSBLOCKED = None
CLIENTS = None

y = top = 5
x = 5
if not buttonA.value: # just button A pressed
draw.text((x, y), IP, font=font, fill="#FFFF00")
y += font.getbbox(IP)[3]
Expand All @@ -121,13 +113,19 @@
y += font.getbbox(IP)[3]
draw.text((x, y), HOST, font=font, fill="#FFFF00")
y += font.getbbox(HOST)[3]
draw.text((x, y), "Ads Blocked: {}".format(str(ADSBLOCKED)), font=font, fill="#00FF00")
y += font.getbbox(str(ADSBLOCKED))[3]
draw.text((x, y), "Clients: {}".format(str(CLIENTS)), font=font, fill="#0000FF")
y += font.getbbox(str(CLIENTS))[3]
draw.text((x, y), "DNS Queries: {}".format(str(DNSQUERIES)), font=font, fill="#FF00FF")
y += font.getbbox(str(DNSQUERIES))[3]
if ADSBLOCKED is not None:
txt = f"Ads Blocked: {ADSBLOCKED}"
draw.text((x, y), txt, font=font, fill="#00FF00")
y += font.getbbox(txt)[3]
if CLIENTS is not None:
txt = f"Clients: {CLIENTS}"
draw.text((x, y), txt, font=font, fill="#0000FF")
y += font.getbbox(txt)[3]
if DNSQUERIES is not None:
txt = f"DNS Queries: {DNSQUERIES}"
draw.text((x, y), txt, font=font, fill="#FF00FF")
y += font.getbbox(txt)[3]

# Display image.
disp.image(image, rotation)
disp.image(image)
time.sleep(.1)