Raspberry Pi: CPU-Auslastung als Diagramm auf OLED-Display

Im vorherigen Beitrag haben wir uns ein paar Grundlagen zum 0,96'' OLED-Display mit 128x64 Pixeln angeeignet und hier gehen wir ein Stück weiter: Wir lesen die CPU-Auslastung vom Raspberry Pi aus und stellen diese als Diagramm auf dem Display dar. Die Skalierung des Diagramms soll sich dabei abhängig von den dargestellten Werten automatisch anpassen. Zusätzlich wird der aktuelle Wert als Text angezeigt.

Raspberry Pi: CPU-Auslastung im Diagramm

Raspberry Pi: CPU-Auslastung im Diagramm

Benötigte Bibliotheken

Um an die benötigten Informationen zu gelangen, nutzen wir psutil – eine Bibliothek, mit der man Systemwerte auslesen kann. Zur Installation benötigen wir PIP. Wer das nicht hat, muss das vorher noch installieren:

$ sudo apt-get install python-pip

Dann machen wir direkt mit dem Paket weiter:

$ sudo pip install psutil

Wir lesen mit psutil nur die CPU-Auslastung aus, die Bibliothek kann aber noch mehr liefern. Einen genauen Überblick darüber könnt ihr euch hier verschaffen.

Der Code

Wer den vorherigen Beitrag aufmerksam gelesen hat, wird mit dem Code schnell zurecht kommen. Daher gehe ich nur auf das Auslesen der Werte und den Aufbau des Diagramms ein.

#!/usr/bin/python
# coding=utf-8

# Einbindung der notwendigen Grundbibliotheken
import os, sys, time

# Einbindung 0,96 Zoll OLED Display 128x64 Pixel
from lib_oled96 import ssd1306
from smbus import SMBus
from PIL import ImageFont

# Einbindung von Bibliotheken für die gewünschten Funktionen
import psutil

# ----------------------------------------------------------------------------
#  Variablen anlegen
# ----------------------------------------------------------------------------
cpuList = []
scale = 100

# ----------------------------------------------------------------------------
#  Display einrichten
# ----------------------------------------------------------------------------

i2cbus = SMBus(1)		# 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)

# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas

# Display zum Start löschen
oled.cls()
oled.display()

# Schriftarten festlegen
FreeSans08 = ImageFont.truetype('FreeSans.ttf', 8)
FreeSans11 = ImageFont.truetype('FreeSans.ttf', 11)

# ----------------------------------------------------------------------------
#  Hauptprogramm
# ----------------------------------------------------------------------------

while True:
	try:
		# Inhalt des Displays bei jedem Durchlauf neu aufbauen
		draw.rectangle((0,0, oled.width, oled.height), outline=0, fill=0)
	
		# CPU-Auslastung auslesen
		cpu_val = psutil.cpu_percent(interval=1)

		# Momentanwert anzeigen
		draw.text((0, 0), "CPU: " + str(cpu_val) + " %", font=FreeSans11, fill=255)

		# Werte für Diagramm speichern und Länge auf 110 Einträge begrenzen
		cpuList.append(cpu_val)
		if len(cpuList) > 110:
			cpuList.pop(0)

		# Skalierung des Diagramms
		max_val = max(cpuList)

		if max_val <= 100.0:
			scale = 100
		if max_val <= 90.0:
			scale = 90
		if max_val <= 80.0:
			scale = 80
		if max_val <= 70.0:
			scale = 70
		if max_val <= 60.0:
			scale = 60
		if max_val <= 50.0:
			scale = 50
		if max_val <= 40.0:
			scale = 40	
		if max_val <= 30.0:
			scale = 30
		if max_val <= 20.0:
			scale = 20
		if max_val <= 10.0:
			scale = 10

		# Achsen zeichnen
		draw.line((12, 60, oled.width, 60), fill=255)	# X
		draw.line((15, 20, 15, 63), fill=255)			# Y
		draw.line((12, 20, 15, 20), fill=255)			# oberster Skalenwert

		# obersten Y-Wert beschriften
		draw.text((0, 16), str(scale), font=FreeSans08, fill=255)

		# X-Koordinate für ersten Wert festlegen
		X = 17

		# Diagrammwerte zeichnen
		for n in range(len(cpuList)):
			Y = float(40 / float(scale) * cpuList[n])
			draw.line((X, 58, X, 58-Y), fill=255)
			X = X + 1

		# Daten am Display ausgeben
		oled.display()

		# Ausgabe der aktuellen Werte auf der Kommandozeile zum Debuggen
		#print str(cpu_val) + "     |     " + str(max_val) + "     |     " + str(scale) + "     |     " + str(40.0 / float(scale) * float(cpu_val))

	except KeyboardInterrupt:
		oled.cls()
		oled.display()
		sys.exit(0)

Funktionsweise

Grob kann man das Ganze so beschreiben:

Das Display kann, durch seine Breite vorgegeben 110 Einzelwerte darstellen. Den restlichen Platz benötigen wir für die Y-Achse. Die Einzelwerte reihen wir mit 1px breiten Linien aneinander, bis das Display gefüllt ist. So ergibt sich unser Diagramm.

Momentanwerte speichern

Auf Zeile 18 erzeugen wir eine leere Liste und darunter legen wir den Skalenendwert der Y-Achse auf 100 fest. Die momentane CPU-Auslastung lesen wir mittels psutil auf Zeile 49 aus und stellen diese auf Zeile 52 als Text dar.

Mit dem Code auf den Zeilen 55-57 hängen wir Durchlauf für Durchlauf den aktuellen Momentanwert der CPU-Auslastung an die anfangs noch leere Liste an. Diese baut sich somit immer weiter auf. Sie soll jedoch nicht ewig lang werden, da unser Display ja auch nicht ewig breit ist. In der hier verwendeten Darstellung passen 110 Werte in das Diagramm auf dem Display. Somit muss die Liste mit den CPU-Werten auch nicht länger sein. Wenn der 111. Eintrag angehängt wird, wird der erste aus der Liste entfernt (cpuList.pop(0)), sodass die Liste danach wieder 110 Einträge besitzt.

Y-Achse skalieren

Bei geringer CPU-Last und einer Skalierung der Y-Achse, dass 0…100% angezeigt werden können, würde man die meiste Zeit überhaupt keine Werte im Diagramm sehen. Daher soll die Skalierung der Y-Achse automatisch angepasst und die Darstellung der Einzelwerte optimal auf den zur Verfügung stehenden Platz zugeschnitten werden. Dazu ermitteln wir den größten Wert der Liste (Zeile 60) und runden ihn auf 10er-Stellen auf (Zeilen 62-81). Der ermittelte Wert dient als Faktor für die Höhe der zu zeichnenden Linien.

Diagramm zeichnen

Auf den Zeilen 95 bis 98 iterieren wir über alle Werte in der Liste und zeichnen für jeden Einzelwert eine Linie, deren Länge abhängig vom Skalierungsfaktor ist. Die Berechnung lautet wie folgt:

<Diagrammhöhe> / <Skalierungsfaktor> * <CPU-Auslastung>

Die Diagrammhöhe ergibt sich daraus, wie man den Platz auf dem Display dafür freihält. In meinem Beispiel sind 40 Pixel für die Werte vorgesehen. Den Skalierungsfaktor haben wir im vorherigen Abschnitt betrachtet und die CPU-Auslastung haben wir mit psutil erfasst.

Ein Beispiel: In unserer Liste befinden sich jede Menge bunte Werte zwischen 0 und 19. Der Skalierungsfaktor wird demzufolge 20 sein. Der Wert, der gezeichnet werden soll, beträgt 14. Das führt uns zu folgender Formel:

Linienlänge = 40px / 20 * 14% = 28px

Der Startpunkt der Werte ist auf 58px festgelegt. Von dieser Höhe werden die Linien aufwärts gezeichnet.

Auf Zeile 92 haben wir zuvor noch die X-Koordinate für den ersten Wert festgelegt. Bei jedem Durchlauf der for-Schleife wird X um 1 erhöht, sodass jede weitere Linie um je einen Pixel nach rechts verschoben gezeichnet wird.

Debuggen

Wer die im Diagramm angezeigten Werte mit der Berechnung vergleichen möchte, kann Zeile 104 einkommentieren. Hier werden die aktuelle CPU-Auslastung, der höchste Wert in der Liste, der Skalierungsfaktor und die berechnete Linienlänge ausgegeben.

Raspberry Pi: CPU-Auslastung im Diagramm

Raspberry Pi: CPU-Auslastung im Diagramm

Sebastian

Sebastian

...ist staatlich geprüfter Techniker für Elektrotechnik, Schwerpunkt Prozessautomatisierung und Energietechnik. Die Themen Automatisierung und Programmierung haben es ihm besonders angetan.
Außerdem ist er für jede technische Spielerei zu haben 😉
Sebastian

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Translate »