Last active
November 21, 2025 15:36
-
-
Save gboone/40dc2a58c0f608a7b6bf2a4fe623ec0b to your computer and use it in GitHub Desktop.
Script to display some basic info from a pihole on an adafruit 1.14" tft display. Buttons currently disabled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #! /usr/bin/python3 | |
| # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries | |
| # SPDX-License-Identifier: MIT | |
| # -*- coding: utf-8 -*- | |
| # to test, edit /etc/rc.local then reboot | |
| import time | |
| import subprocess | |
| import digitalio | |
| import board | |
| import socket | |
| import sys | |
| import signal | |
| from PIL import Image, ImageDraw, ImageFont | |
| from adafruit_rgb_display import st7789 | |
| # Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4): | |
| cs_pin = digitalio.DigitalInOut(board.CE0) | |
| dc_pin = digitalio.DigitalInOut(board.D25) | |
| reset_pin = None | |
| # Config for display baudrate (default max is 24mhz): | |
| BAUDRATE = 64000000 | |
| # Setup SPI bus using hardware SPI: | |
| 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, | |
| ) | |
| # 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("RGBA", (width, height)) | |
| rotation = 270 | |
| BLACK = (0,0,0) | |
| WHITE = (255,255,255) | |
| # Get drawing object to draw on image. | |
| draw = ImageDraw.Draw(image) | |
| # Draw a black filled box to clear the image. | |
| draw.rectangle((0, 0, width, height), outline=0, fill=BLACK) | |
| 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 | |
| y = top | |
| # 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/DejaVuSansMono.ttf", 20) | |
| # Turn on the backlight | |
| backlight = digitalio.DigitalInOut(board.D22) | |
| backlight.switch_to_output() | |
| backlight.value = True | |
| # Watch them buttons | |
| buttonA = digitalio.DigitalInOut(board.D23) | |
| buttonB = digitalio.DigitalInOut(board.D24) | |
| buttonA.switch_to_input() | |
| buttonB.switch_to_input() | |
| # check an internet connection | |
| def is_connected(): | |
| try: | |
| socket.create_connection(("1.1.1.1", 53)) | |
| return True | |
| except OSError: | |
| pass | |
| return False | |
| # get the current CPU load | |
| def getCPU(): | |
| getCPU = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'" | |
| return subprocess.check_output(getCPU, shell=True).decode("utf-8") | |
| # get the current IP address | |
| def getIP(): | |
| getIP = "hostname -I | cut -d' ' -f1" | |
| return "IP: " + subprocess.check_output(getIP, shell=True).decode("utf-8") | |
| # get the current disk usage | |
| def getDF(): | |
| getDF = 'df -h | awk \'$NF=="/"{printf "Disk: %d/%d GB %s full", $3,$2,$5}\'' | |
| return subprocess.check_output(getDF, shell=True).decode("utf-8") | |
| # get the pihole's status | |
| def getPiHoleStatus(): | |
| getPiholeStatus = "pihole status | tail -n1 | awk 'NF>1{print $NF}'" | |
| piholeStatus = subprocess.check_output(getPiholeStatus, shell=True).decode("utf-8").strip() | |
| return "Blocking: {}".format(piholeStatus) | |
| def getConnection(): | |
| return "Connected" if is_connected() else "Disconnected" | |
| def piHoleToggleState(): | |
| status = getPiHoleStatus() | |
| toggleAction = "disable" if status.split()[-1] == "enabled" else "enable" | |
| toggleText = "{} with pi remote".format(toggleAction) | |
| return (toggleAction, toggleText) | |
| def togglePiHole(action): | |
| return subprocess.run("pihole {}".format(action), shell=True) | |
| def clearfix(y): | |
| height = y + 22 | |
| draw.rectangle((-1, y, width, height), outline=0, fill=BLACK) | |
| def exitClear(): | |
| draw.rectangle((-1, 0, width, height), outline=0, fill=BLACK) | |
| disp.image(image, rotation) | |
| backlight.value = False | |
| def signal_handler(sig, frame): | |
| exitClear() | |
| sys.exit(0) | |
| # draw image placeholders for each line | |
| ip = getIP() | |
| cpu = getCPU() | |
| disk = getDF() | |
| piHoleStatus = getPiHoleStatus() | |
| connected = getConnection() | |
| toggleAction = piHoleToggleState()[1] | |
| #set appropriate spacing for six lines | |
| ONE = 0 | |
| TWO = 22 | |
| THREE = 44 | |
| FOUR = 66 | |
| FIVE = 88 | |
| SIX = 110 | |
| # draw initial text lines | |
| draw.text((x, ONE), ip, font=font, fill=WHITE) | |
| draw.text((x, TWO), cpu, font=font, fill=WHITE) | |
| draw.text((x, THREE), disk, font=font, fill=WHITE) | |
| draw.text((x, FOUR), piHoleStatus, font=font, fill=WHITE) | |
| draw.text((x, FIVE), connected, font=font, fill=WHITE) | |
| draw.text((x, SIX), toggleAction, font=font, fill=WHITE) | |
| signal.signal(signal.SIGINT, signal_handler) | |
| signal.signal(signal.SIGTERM, signal_handler) | |
| try: | |
| while True: | |
| x = 0 | |
| currIP = getIP() | |
| currCPU = getCPU() | |
| currDisk = getDF() | |
| currPiHoleStatus = getPiHoleStatus() | |
| # button status | |
| toggleState = piHoleToggleState() | |
| nextPiHoleAction = toggleState[0] | |
| newToggleAction = toggleState[1] | |
| # internet connection status | |
| currConnection = getConnection() | |
| # Write lines of text. | |
| #draw.text((x,y), "Hi", font=font, fill="#FFFFFF") | |
| # Current IP address | |
| if currIP != ip: | |
| clearfix(ONE) | |
| draw.text((x, ONE), currIP, font=font, fill=WHITE) | |
| # Current CPU usage | |
| if currCPU != cpu: | |
| clearfix(TWO) | |
| draw.text((x, TWO), currCPU, font=font, fill=WHITE) | |
| # Disk usage | |
| if currDisk != disk: | |
| clearfix(THREE) | |
| draw.text((x, THREE), currDisk, font=font, fill=WHITE) | |
| # Print internet status | |
| #draw.text((x,y), connected, font=font, fill=WHITE) | |
| # Check the buttons | |
| # Because our screen is flipped 180º the B button is the top button. | |
| if currPiHoleStatus != piHoleStatus: | |
| clearfix(FOUR) | |
| draw.text((x, FOUR), currPiHoleStatus, font=font, fill=WHITE) | |
| clearfix(FIVE) | |
| draw.text((x, FIVE), newToggleAction, font=font, fill=WHITE) | |
| if currConnection != connected: | |
| clearfix(SIX) | |
| draw.text((x, SIX), currConnection, font=font, fill=WHITE) | |
| # Display image. | |
| disp.image(image, rotation) | |
| time.sleep(2) | |
| #draw.rectangle((0,0, width, height), outline=0, fill="#FFFFFF") | |
| except KeyboardInterrupt: | |
| pass | |
| finally: | |
| exitClear() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment