NanoHat OLED to Display CPU % on each core
Posted: Thu Dec 21, 2017 3:45 pm
I wanted a screen that would show the CPU % of all 4 cores. Much like htop does.
I modified the bakebit_nanohat_oled.py source file. (though this forum wont let me attach a .py file. so included below.
Copy and paste into your bakebit_nanohat_oled.py source file, located in
NanoHatOLED Mine/BakeBit/Software/Python folder, and reboot.
Pressing K2 the first time will show the stock screen, pressing it again will show this new one.
Currently I am running this with my NanoPi NEO Air, the only extra step I had to do is "pip install Pillow" for it to work.
P.S. I am just scratching the surface learning embedded Linux, and Python so take it into consideration.
I modified the bakebit_nanohat_oled.py source file. (though this forum wont let me attach a .py file. so included below.
Copy and paste into your bakebit_nanohat_oled.py source file, located in
NanoHatOLED Mine/BakeBit/Software/Python folder, and reboot.
Pressing K2 the first time will show the stock screen, pressing it again will show this new one.
Currently I am running this with my NanoPi NEO Air, the only extra step I had to do is "pip install Pillow" for it to work.
P.S. I am just scratching the surface learning embedded Linux, and Python so take it into consideration.
Code: Select all
#!/usr/bin/env python
#
# BakeBit example for the basic functions of BakeBit 128x64 OLED (http://wiki.friendlyarm.com/wiki/index.php/BakeBit_-_OLED_128x64)
#
# The BakeBit connects the NanoPi NEO and BakeBit sensors.
# You can learn more about BakeBit here: http://wiki.friendlyarm.com/BakeBit
#
# Have a question about this example? Ask on the forums here: http://www.friendlyarm.com/Forum/
#
# NOTE: When Instlling on NanoPiAir you may need to: "pip isntall Pillow"
# for this to work
#
'''
## License
The MIT License (MIT)
BakeBit: an open source platform for connecting BakeBit Sensors to the NanoPi NEO.
Copyright (C) 2016 FriendlyARM
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
import bakebit_128_64_oled as oled
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import time
import sys
import subprocess
import threading
import signal
import os
import socket
import psutil
global width
width=128
global height
height=64
global pageCount
pageCount=2
global pageIndex
pageIndex=0
global showPageIndicator
showPageIndicator=False
oled.init() #initialze SEEED OLED display
oled.setNormalDisplay() #Set display to normal mode (i.e non-inverse mode)
oled.setHorizontalMode()
global drawing
drawing = False
global image
image = Image.new('1', (width, height))
global draw
draw = ImageDraw.Draw(image)
global fontb24
fontb24 = ImageFont.truetype('DejaVuSansMono-Bold.ttf', 24);
global font14
font14 = ImageFont.truetype('DejaVuSansMono.ttf', 14);
global smartFont
smartFont = ImageFont.truetype('DejaVuSansMono-Bold.ttf', 10);
global fontb14
fontb14 = ImageFont.truetype('DejaVuSansMono-Bold.ttf', 14);
global font11
font11 = ImageFont.truetype('DejaVuSansMono.ttf', 11);
global font10
font10 = ImageFont.truetype('DejaVuSansMono.ttf', 10);
global font12
font12 = ImageFont.truetype('DejaVuSansMono.ttf', 12);
global lock
lock = threading.Lock()
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except:
IP = '127.0.0.1'
finally:
s.close()
return IP
def get_temp():
tempI = int(open('/sys/class/thermal/thermal_zone0/temp').read());
if tempI>1000:
tempI = tempI/1000
tempStr = "CPU TEMP: %sC" % str(tempI)
return tempStr
def draw_page():
global drawing
global image
global draw
global oled
global font
global font14
global smartFont
global width
global height
global pageCount
global pageIndex
global showPageIndicator
global width
global height
global lock
lock.acquire()
is_drawing = drawing
page_index = pageIndex
lock.release()
if is_drawing:
return
lock.acquire()
drawing = True
lock.release()
# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Draw current page indicator
if showPageIndicator:
dotWidth=4
dotPadding=2
dotX=width-dotWidth-1
dotTop=(height-pageCount*dotWidth-(pageCount-1)*dotPadding)/2
for i in range(pageCount):
if i==page_index:
draw.rectangle((dotX, dotTop, dotX+dotWidth, dotTop+dotWidth), outline=255, fill=255)
else:
draw.rectangle((dotX, dotTop, dotX+dotWidth, dotTop+dotWidth), outline=255, fill=0)
dotTop=dotTop+dotWidth+dotPadding
if page_index==0:
text = time.strftime("%A")
draw.text((2,2),text,font=font14,fill=255)
text = time.strftime("%e %b %Y")
draw.text((2,18),text,font=font14,fill=255)
text = time.strftime("%X")
draw.text((2,40),text,font=fontb24,fill=255)
elif page_index==1:
# 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
IPAddress = get_ip()
cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'"
CPU = subprocess.check_output(cmd, shell = True )
cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %.f%%\", $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 )
draw.text((x, top), "IP: " + str(IPAddress), font=font12, fill=255)
draw.text((x, top+20), str(CPU), font=font12, fill=255)
draw.text((x, top+35), str(MemUsage), font=font12, fill=255)
draw.text((x, top+50), str(Disk), font=font12, fill=255)
elif page_index==2:
top=0
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)
# Get each of the 4 cores CPU useage
cpu = psutil.cpu_percent(interval=1, percpu=True)
temp1r = "[ ]%3d" % int(cpu[0])
temp2r = "[ ]%3d" % int(cpu[1])
temp3r = "[ ]%3d" % int(cpu[2])
temp4r = "[ ]%3d" % int(cpu[3])
# Print the CPU's %
draw.text((0, top ), temp1r, font=font10, fill=255)
draw.text((0, top + 10), temp2r, font=font10, fill=255)
draw.text((0, top + 20), temp3r, font=font10, fill=255)
draw.text((0, top + 30), temp4r, font=font10, fill=255)
# Draw the graphs
for x in range(0, int(cpu[0])):
draw.line((x+4, 3, x+4, 7), fill=255)
for x in range(0, int(cpu[1])):
draw.line((x+4, 13, x+4, 17), fill=255)
for x in range(0, int(cpu[2])):
draw.line((x+4, 23, x+4, 27), fill=255)
for x in range(0, int(cpu[3])):
draw.line((x+4, 33, x+4, 37), fill=255)
tempStr = get_temp()
draw.text((15, top+53), tempStr, font=font11, fill=255)
elif page_index==3: #shutdown -- no
draw.text((2, 2), 'Shutdown?', font=fontb14, fill=255)
draw.rectangle((2,20,width-4,20+16), outline=0, fill=0)
draw.text((4, 22), 'Yes', font=font11, fill=255)
draw.rectangle((2,38,width-4,38+16), outline=0, fill=255)
draw.text((4, 40), 'No', font=font11, fill=0)
elif page_index==4: #shutdown -- yes
draw.text((2, 2), 'Shutdown?', font=fontb14, fill=255)
draw.rectangle((2,20,width-4,20+16), outline=0, fill=255)
draw.text((4, 22), 'Yes', font=font11, fill=0)
draw.rectangle((2,38,width-4,38+16), outline=0, fill=0)
draw.text((4, 40), 'No', font=font11, fill=255)
elif page_index==5:
draw.text((2, 2), 'Shutting down', font=fontb14, fill=255)
draw.text((2, 20), 'Please wait', font=font11, fill=255)
oled.drawImage(image)
lock.acquire()
drawing = False
lock.release()
def is_showing_power_msgbox():
global pageIndex
lock.acquire()
page_index = pageIndex
lock.release()
if page_index==3 or page_index==4:
return True
return False
def update_page_index(pi):
global pageIndex
lock.acquire()
pageIndex = pi
lock.release()
def receive_signal(signum, stack):
global pageIndex
lock.acquire()
page_index = pageIndex
lock.release()
if page_index==5:
return
if signum == signal.SIGUSR1:
#print 'K1 pressed'
if is_showing_power_msgbox():
if page_index==3:
update_page_index(4)
else:
update_page_index(3)
else:
pageIndex=0
draw_page()
if signum == signal.SIGUSR2:
#print 'K2 pressed %d' % page_index
if is_showing_power_msgbox():
if page_index==4:
update_page_index(5)
else:
update_page_index(0)
else:
if page_index==1:
update_page_index(2)
elif page_index==2:
update_page_index(1)
else:
update_page_index(1)
draw_page()
if signum == signal.SIGALRM:
#print 'K3 pressed'
if is_showing_power_msgbox():
update_page_index(0)
else:
update_page_index(3)
draw_page()
image0 = Image.open('friendllyelec.png').convert('1')
oled.drawImage(image0)
time.sleep(2)
signal.signal(signal.SIGUSR1, receive_signal)
signal.signal(signal.SIGUSR2, receive_signal)
signal.signal(signal.SIGALRM, receive_signal)
while True:
try:
draw_page()
lock.acquire()
page_index = pageIndex
lock.release()
if page_index==5:
time.sleep(2)
while True:
lock.acquire()
is_drawing = drawing
lock.release()
if not is_drawing:
lock.acquire()
drawing = True
lock.release()
oled.clearDisplay()
break
else:
time.sleep(.1)
continue
time.sleep(1)
os.system('systemctl poweroff')
break
time.sleep(1)
except KeyboardInterrupt:
break
except IOError:
print ("Error")