- Raspberry Pi-4 под управлением Buster с использованием Python 3.7 с крышкой Adafruit 128x32 2,23 дюйма OLED, подключенной к контактам GPIO. Ссылка: https://learn.adafruit.com/adafruit-2-2 ... led-bonnet
- Оригинальная версия сценарий, который я использую, можно найти по адресу: https://learn.adafruit.com/adafruit-2-2 ... ce-3064554
При запуске программы Python через окно терминала , CTL-C не всегда обеспечивает желаемое завершение работы. При запуске внутри Thonny он работает всегда.
Обратите внимание на следующий скрипт Python, который был дословно взят с веб-сайта Adafruit для тестирования их «Bonnet» OLED Raspberry Pi 128x32.
Я изменил его, добавив некоторый код для захвата и обработки прерываний сигналов, чтобы он очищал и закрывал дисплей по завершении программы.
А именно:
Код: Выделить всё
#!/usr/bin/python3.7
# SPDX-FileCopyrightText: 2020 Tony DiCola, James DeVito,
# and 2020 Melissa LeBlanc-Williams, for Adafruit Industries
# SPDX-License-Identifier: MIT
# This example is for use on (Linux) computers that are using CPython with
# Adafruit Blinka to support CircuitPython libraries. CircuitPython does
# not support PIL/pillow (python imaging library)!
# Modified 2024/10/12 by Jim Harris to allow for signal capture
# and a graceful shutdown
import os
import signal
import sys
from threading import Condition, Thread, Event
import time
import subprocess
from board import SCL, SDA, D4
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1305
# check if it's ran with Python3
assert sys.version_info[0:1] == (3,)
# for triggering the shutdown procedure when a signal is detected
keyboard_trigger = Event()
def signal_handler(signal, frame):
print('\nSignal detected. Stopping threads.')
keyboard_trigger.set()
# registering both types of signals
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Get PID of this running script
pid = os.getpid()
# Define the Reset Pin
oled_reset = digitalio.DigitalInOut(D4)
# Create the I2C interface.
i2c = busio.I2C(SCL, SDA)
# Create the SSD1305 OLED class.
# The first two parameters are the pixel width and pixel height. Change these
# to the right size for your display!
disp = adafruit_ssd1305.SSD1305_I2C(128, 32, i2c, reset=oled_reset)
# Clear display.
disp.fill(0)
disp.show()
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new("1", (width, height))
# 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=0)
# 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
# Load default font.
#font = ImageFont.load_default()
# 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', 9)
print("Started system statistics printout as PID", pid)
# Main drawing routine
#while True:
while not keyboard_trigger.is_set():
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=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 = 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")
# Write four lines of text.
draw.text((x, top + 0), "IP: " + IP, font=font, fill=255)
draw.text((x, top + 8), CPU, font=font, fill=255)
draw.text((x, top + 16), MemUsage, font=font, fill=255)
draw.text((x, top + 25), Disk, font=font, fill=255)
# Display image.
disp.image(image)
disp.show()
time.sleep(0.1)
# until some keyboard event is detected
print("\nA keyboard event was detected.")
print("Clearing and shutting down display")
# Clear display.
disp.fill(0)
disp.show()
sys.exit(0)
Запуск изнутри Thonny всегда приводит к следующему выводу внутри Окно терминала Тонни (REPL).
Код: Выделить всё
Python 3.7.3 (/usr/bin/python3)
>>> %cd /home/pi/startup_scripts
>>> %Run Stats.py
Started system statistics printout as PID 24225
Signal detected. Stopping threads.
A keyboard event was detected.
Clearing and shutting down display
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>>
Случай 2: Запуск в окне терминала.
При запуске в терминале я получаю следующее:
Попытка 1: Отправка явного сигнала уничтожения из другое окно терминала:
Код: Выделить всё
pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 15893
Signal detected. Stopping threads.
A keyboard event was detected.
Clearing and shutting down display
pi@Adafruit128x32:~/startup_scripts $
Попытка 2: завершение в работающем окне терминала с помощью CTL-C
Попытка 1:
Код: Выделить всё
pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 16921
^C
Signal detected. Stopping threads.
A keyboard event was detected.
Clearing and shutting down display
pi@Adafruit128x32:~/startup_scripts $
Код: Выделить всё
pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 17587
^C
Signal detected. Stopping threads.
Traceback (most recent call last):
File "./Stats.py", line 104, in
Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")
File "/usr/lib/python3.7/subprocess.py", line 395, in check_output
**kwargs).stdout
File "/usr/lib/python3.7/subprocess.py", line 487, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'df -h | awk '$NF=="/"{printf "Disk: %d/%d GB %s", $3,$2,$5}'' died with .
pi@Adafruit128x32:~/startup_scripts $
Я подозреваю, что происходит то, что выполняются другие фрагменты библиотечного кода, которые улавливают сигнал клавиатуры CTL-C, и «куски библиотечного кода» не передают исключение «вверх по лестнице» процессу, в котором я обрабатываю ошибку.
Вопрос:
- Почему это происходит?
- Есть ли способ гарантировать, что мой код захватывает сигнал клавиатуры, чтобы его можно было завершить без проблем, без необработанных исключений, которые обычно случаются?
Подробнее здесь: https://stackoverflow.com/questions/790 ... trl-c-prop