mklements / OLED_Stats

OLED Stats Display Script For Raspberry Pi
MIT License
87 stars 39 forks source link

Script won't load on reboot #9

Open 0rig1nal opened 11 months ago

0rig1nal commented 11 months ago

I tried having the file simply in /home/pj but it didn't won't even I tried to run after reboot manually. Now I have it in oled dir with other files like PixelOperator.ttf and the script will start if triggered manually. But after reboot it always throws the attached log

Crontab @reboot python3 /home/pj/oled/stats.py >> /home/pj/oled/cron.log 2>&1

Error cat log:

Traceback (most recent call last):
  File "/home/pj/oled/stats.py", line 44, in <module>
    font = ImageFont.truetype('PixelOperator.ttf', 16)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 852, in truetype
    return freetype(font)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 849, in freetype
    return FreeTypeFont(font, size, index, encoding, layout_engine)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 209, in __init__
    self.font = core.getfont(
OSError: cannot open resource

OS: rasberry pi lite

0rig1nal commented 11 months ago

I am no expert in this so consider this as a dirty workaround instead of a solution. I also added that the oled will "turn off" on shutdown/reboot.

Adjustments: Command for the script to run after reboot didn't work for me so in crontab I replaced:

@reboot python3 /home/pi/stats.py &

with:

@reboot nohup python3 /home/pj/oled/stats.py &

Then I adjusted the stats.py file:

import time
import board
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
import subprocess
import threading  # Import the threading module

# Define the Reset Pin
oled_reset = digitalio.DigitalInOut(board.D4)

# Display Parameters
WIDTH = 128
HEIGHT = 64
BORDER = 5

# Display Refresh
LOOPTIME = 1.0

# Use for I2C.
i2c = board.I2C()
oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C, reset=oled_reset)
# Clear display.
oled.fill(0)
oled.show()

# Create a blank image for drawing.
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# Load the font
font = ImageFont.truetype('PixelOperator.ttf', 16)

draw.rectangle((0, 0, oled.width, oled.height), outline=255, fill=255)

# Main loop
# Function to run OLED display in a background thread
def run_oled_display():
    while True:
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

        # Shell scripts for system monitoring
        cmd = "hostname -I | cut -d\' \' -f1"
                IP = subprocess.check_output(cmd, shell=True)
        cmd = "top -bn1 | grep load | awk '{printf \"CPU: %.2f\", $(NF-2)}'"
        CPU = subprocess.check_output(cmd, shell=True)
        cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %.2f%%\", $3,$2,$3*100/$2 }'"
        MemUsage = subprocess.check_output(cmd, shell=True)
        cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%dGB %s\", $3,$2,$5}'"
        Disk = subprocess.check_output(cmd, shell=True)
        cmd = "vcgencmd measure_temp |cut -f 2 -d '='"
        Temp = subprocess.check_output(cmd, shell=True)

        # Pi Stats Display
        draw.text((0, 0), "IP: " + str(IP, 'utf-8'), font=font, fill=255)
        draw.text((0, 16), str(CPU, 'utf-8') + "LA", font=font, fill=255)
        draw.text((80, 16), str(Temp, 'utf-8'), font=font, fill=255)
        draw.text((0, 32), str(MemUsage, 'utf-8'), font=font, fill=255)
        draw.text((0, 48), str(Disk, 'utf-8'), font=font, fill=255)

        # Display image
        oled.image(image)
        oled.show()
        time.sleep(LOOPTIME)

oled_thread = threading.Thread(target=run_oled_display)
# Start the thread
oled_thread.start()

# Join the thread (optional, to ensure it finishes when the main program exits)
# oled_thread.join()

After that I created a shutdown script (the script only fills the board with "nothing" but it will still consume power - didn't manage to turn it off)

import time
import board
import busio
import digitalio
import subprocess

from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306

import subprocess

# Define the Reset Pin
oled_reset = digitalio.DigitalInOut(board.D4)

# Display Parameters
WIDTH = 128
HEIGHT = 64
BORDER = 5

# Display Refresh
LOOPTIME = 1.0

# Use for I2C.
i2c = board.I2C()
oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C, reset=oled_reset)

# Stop display update
try:
    subprocess.run(['/usr/bin/pkill', '-f', 'stats.py'])
except subprocess.CalledProcessError as e:
    # Handle any errors that might occur when running the command
    print(f"Error: {e}")

# Clear display.
oled.fill(0)
oled.show()

And lastly I created a system service oled_shutdown.service in /etc/systemd/system which calls the shutdown script on shutdown/reboot.

[Unit]
Description=Kill stats.py on shutdown/reboot

[Service]
Type=oneshot
RemainAfterExit=true
ExecStop=/usr/bin/python3 /home/pj/oled/shutdown.py

[Install]
WantedBy=multi-user.target

And lastly to power up the service just write: • sudo systemctl daemon-reload #(reloads services) • sudo systemctl start oled_shutdown.service

Now everything is setup and we can check if the service is running by: • sudo systemctl status oled_shutdown.service