Tuesday, August 9, 2016

An SSD1306 OLED System Monitor for the Raspberry Pi

 
Here's a simple system monitor for the Raspberry Pi using an SSD1306 OLED and a BME280 sensor (to get temperature, barometric pressure and humidity). You'll need to construct an iC2 'Y' cable and plug into the GPIO pins on your Pi. Make sure to enable iC2 for Raspbian, then download and install rm-hull's Github SSD1306 library, along with Matt Hawkin's bme280.py script. Put everything into the same directory.

After testing to make sure that your sensor and OLED are working, use this script to get a host of information about your Pi, ambient conditions and even local weather.

Here's the script:

#!/usr/bin/env python
# myssd.py version 0.8 - a simple system monitor for the Raspberry Pi
# adapted from rmhull's wonderful ssd1306 Python lib by bball@tux.org
# crafted for the dual-color 128x96 OLED w/yellow top area
# 060316 - added date, CPU temp, wlan0 IP addr, memory, sd card used
# 060416 - added splash screen, general code cleanup, KB output for memory
# 061316 - added local current WX conditions
# 080616 - added wifi, serial number, uptime with text wrap
# 080816 - added BME280 output of temp, pressure, and humidity

import os
import psutil
from lib_oled96 import ssd1306
from time import sleep
from datetime import datetime
from PIL import ImageFont, ImageDraw, Image
#font = ImageFont.load_default()

from smbus import SMBus                  #  These are the only two variant lines !!
i2cbus = SMBus(1)                        #
oled = ssd1306(i2cbus)

draw = oled.canvas  
# set font to 13 for yellow area
font = ImageFont.truetype('FreeSans.ttf', 13)

# show splash screen
draw.text((1, 1), 'RASPBIAN SYSMON', font=font, fill=1)
logo = Image.open('rpi.png')
draw.bitmap((42, 16), logo, fill=1)

oled.display()
sleep(3)
oled.cls()

while True:

 # "draw" onto this canvas, then call display() to send the canvas contents to the hardware.
 draw = oled.canvas  

 # set font to 13 for yellow area
 font = ImageFont.truetype('FreeSans.ttf', 13)

 # get, display date and time
 draw.text((1, 1), str(datetime.now().strftime('%a  %b  %d  %H:%M:%S')), font=font, fill=1)

 # reset font for four smaller lines
 font = ImageFont.truetype('FreeSans.ttf', 10)

 # get, return CPU's current temperature
 def cpu_temp():
    tempF = (((int(open('/sys/class/thermal/thermal_zone0/temp').read()) / 1000)*9/5)+32)
    return "CPU TEMP: %sF" % str(tempF)
 
  # display CPU temp
 draw.text((1, 15),    cpu_temp(),  font=font, fill=1)

 # get, return wlan0's current IP address
 def wlan_ip():
    f = os.popen('ifconfig wlan0 | grep "inet\ addr" | cut -c 21-33')
    ip = str(f.read())
    # strip out trailing chars for cleaner output
    return "WIFI IP: %s" % ip.rstrip('\r\n')

 # display the IP address
 draw.text((1, 28),    wlan_ip(),  font=font, fill=1)

 # get amount of free memory
 def mem_usage():
    usage = psutil.virtual_memory()
    return "MEM USED: %s KB" % (int(str(usage.used)) / 1024)

 # display amount of free memory
 draw.text((1, 41),    mem_usage(),  font=font, fill=1)

 # get disk usage
 def disk_usage(dir):
    usage = psutil.disk_usage(dir)
    return "SD CARD USED: %.0f%%" % (usage.percent)

 # display disk usage
 draw.text((1, 53), disk_usage('/'),  font=font, fill=1)
 oled.display()

 sleep(6)
 oled.cls()      # Oled still on, but screen contents now blacked out

# LARGE display - get wifi wlan0 signal strength
 def get_wifi():
    cmd = "iwconfig wlan0 | grep Signal | /usr/bin/awk '{print $4}' | /usr/bin/cut -d'=' -f2"
    strDbm = os.popen(cmd).read()
    dbm = int(strDbm)
    quality = 2 * (dbm + 100)
    if strDbm:
     return("{0} dbm = {1}%".format(dbm, quality))
    else:
     return("No Wifi")

 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 17)
 draw.text((1, 1), 'WIFI SIGNAL', font=font, fill=1)
 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 15)
 draw.text((1, 30),    get_wifi(),  font=font, fill=1)

 oled.display()
 sleep(2)
 oled.cls()

# LARGE display - uptime
 def get_uptime():
    uptime = os.popen("uptime")
    ut = str(uptime.read())
    # strip out trailing chars for cleaner output
    return "%s" % ut.rstrip('\r\n')

 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 17)
 draw.text((1, 1),    '    UPTIME',  font=font, fill=1)

 # now smaller font needed and wrap text to show info
 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 11)
 import textwrap
 lines = textwrap.wrap(get_uptime(), width=25)
 # what 'line' to start info
 y_text = 20
 w = 1 # we'll always start at left side of OLED
 for line in lines:
    width, height = font.getsize(line)
    draw.text((w, y_text), line, font=font, fill=1)
    y_text += height

 oled.display()
 sleep(2)
 oled.cls()

# LARGE display - get, display serial number
 def get_serial():
    cmd = "cat /proc/cpuinfo | grep Serial | /usr/bin/awk '{print $3}'"
    strDbm = os.popen(cmd).read()
    snum = str(strDbm)
    return "%s" % snum.rstrip('\r\n')

 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 17)
 draw.text((1, 1), 'Serial Number', font=font, fill=1)
 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 14)
 draw.text((1, 30),    get_serial(),  font=font, fill=1)

 oled.display()
 sleep(1)
 oled.cls()

# read bme280 data
 def get_temp():
  from bme280 import readBME280All
 
  temperature,pressure,humidity = readBME280All()
 
  return "%.2f degrees F" % (((temperature)*9/5)+32)

 def get_pressure():
  from bme280 import readBME280All
 
  temperature,pressure,humidity = readBME280All()
 
  return "%.2f inches mercury" % ((pressure)/33.8638866667)

 def get_humidity():
  from bme280 import readBME280All
 
  temperature,pressure,humidity = readBME280All()
 
  return "%.2f%% humidity" % humidity

 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 13)
 draw.text((1, 1), 'Ambient Conditions', font=font, fill=1)

 font = ImageFont.truetype('/home/pi/Downloads/ssd1306-master/FreeSans.ttf', 11)
 draw.text((1, 20),  get_temp(),  font=font, fill=1)
 draw.text((1, 35),  get_pressure(),  font=font, fill=1)
 draw.text((1, 50),  get_humidity(),  font=font, fill=1)

 oled.display()
 sleep(10)
 oled.cls()

 # get, return current WX
 def do_wx():
    f = os.popen('/usr/local/bin/currentwx')
    wx = str(f.read())
    # strip out trailing chars for cleaner output
    return "%s" % wx.rstrip('\r\n')

 font = ImageFont.truetype('FreeSans.ttf', 13)
 draw.text((1, 1),    'CURRENT WEATHER:',  font=font, fill=1)

 # display the WX
 font = ImageFont.truetype('FreeSans.ttf', 12)
 draw.text((1, 15),    'PINELLAS PARK',  font=font, fill=1)
 draw.text((1, 41),    do_wx(),  font=font, fill=1)

 oled.display()
 sleep(10)
 oled.cls()      # Oled still on, but screen contents now blacked out

No comments:

Post a Comment