Final Project Result

The project makes of Pi Zero W, OLED display, Python 3 and few JSON call to build your own Digital Display Device. You can extend our Sample Base class to customise your own Screen for different purpose.





System Information





Current Market Gold Price





















This is all you need to buy before start

1) Raspberry Pi Zero with Pin and at least 8 G Mirco SD Card





2) OLED Display 1.3 inch with keys









3) A very cool and nice Cable (Optional)





The way that it connects to my Pi Zero looks great and relatively easy to place on my Desk





Similar product in Amazon but not exactly the same

4) A plastic Case (Optional)









After that Install the screen and become the following













Setup required Library

1) Install your Own Raspbian OS into your Mirco SD Card





2) Login your Raspbian and upgrade every once if necessary

sudo apt-get dist-upgrade

or

sudo apt-get update





3) Install Library for your OLED

sudo apt-get install python-dev python-pip libfreetype6-dev libjpeg-dev

sudo -H pip install --upgrade pip

sudo apt-get purge python-pip

sudo -H pip install --upgrade luma.oled





## Since we will be using python3, we also need to run the following

sudo python3 -m pip install --upgrade luma.oled





## I am using mscorefonts to display in the OLED, so you also need to install

sudo apt-get install ttf-mscorefonts-installer





4) Now install Adsense library to login your account and get the summary

sudo pip install --upgrade google-api-python-client

sudo pip install --upgrade oauth2client

sudo python -m pip install pytz





###Useful Link to setup Adsense account





###sample code to get account detail and tutorial to generate your Access Key





Try to spend time to verify your access and setup the Key



Create your Main Python class and Connect to OLED



import RPi.GPIO as GPIO import _thread # init GPIO GPIO.setmode(GPIO.BCM) KEY1_PIN = 21 KEY2_PIN = 20 KEY3_PIN = 16 KEY_UP_PIN = 6 KEY_DOWN_PIN = 19 KEY_LEFT_PIN = 5 KEY_RIGHT_PIN = 26 KEY_PRESS_PIN = 13 GPIO.setup(KEY1_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY2_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY3_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY_UP_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY_DOWN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY_LEFT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY_RIGHT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(KEY_PRESS_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up ## Define Reboot / Shutdown Call

def rebootSystem(): command = "/usr/bin/sudo /sbin/shutdown -r now" import subprocess process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) output = process.communicate()[0] print(output) def shutdownSystem(): command = "/usr/bin/sudo /sbin/shutdown now" import subprocess process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) output = process.communicate()[0] print(output) ##Define Key Event

def run_job_key(threadName, delay): pressed = 0 print(threadName + " will be started") while True: ## define key 3 as reboot/shutdown key if GPIO.input(KEY3_PIN): # button is released pressed = pressed + 1 else: # button is pressed: print("Key3 pressed") for i in range(30): if GPIO.input(KEY3_PIN) == False: sleep(0.1) if (i >= 25): shutdownSystem() break else: rebootSystem() break break ##Define Main and register Key

def main(): cmd = "date '+%Y-%m-%d %H:%M:%S'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) date_time = ps.communicate()[0].decode('utf-8').strip() print("Calling main " + str(date_time)) try: _thread.start_new_thread(run_job_key, ("run_job_key", 0,)) except: print("Error: unable to start thread") ## Create Device object for display

width = 128 height = 64 image = Image.new('1', (width, height)) # 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 line = 8 RST = 25 CS = 8 DC = 24 USER_I2C = 0 if USER_I2C == 1: GPIO.setmode(GPIO.BCM) GPIO.setup(RST, GPIO.OUT) GPIO.output(RST, GPIO.HIGH) serial = i2c(port=1, address=0x3c) else: serial = spi(device=0, port=0, bus_speed_hz=8000000, transfer_size=4096, gpio_DC=24, gpio_RST=25) device = sh1106(serial, rotate=2) # sh1106 ## Load Prepared Screen class

loadingScreen = TextScreen("Loading...") screenList = [SystemScreen(), loadingScreen, TimeScreen() ] ## Loop all screen to display result

try: ##Each screen may init a single thread to download required data or calling a external library for i in range(len(screenList)): screenList[i].startThread() while True: device.clear() for i in range(len(screenList)): for count in range(screenList[i].getSleepCount()): with canvas(device) as draw: screenList[i].draw(x, top, width, height, line, draw, device, 255) sleep(screenList[i].getSleepTime()) screenList[i].next() except: print("except") exceptionType, exceptionValue, exceptionTraceback = sys.exc_info() print("*** print_tb:") traceback.print_tb(exceptionTraceback, limit=1, file=sys.stdout) print("*** print_exception:") traceback.print_exception(exceptionType, exceptionValue, exceptionTraceback, limit=2, file=sys.stdout) print("*** print_exc:") traceback.print_exc() print("*** format_exc, first and last line:") formatted_lines = traceback.format_exc().splitlines() print(formatted_lines[0]) print(formatted_lines[-1]) print("*** format_exception:") print(repr(traceback.format_exception(exceptionType, exceptionValue, exceptionTraceback))) print("*** extract_tb:") print(repr(traceback.extract_tb(exceptionTraceback))) print("*** format_tb:") print(repr(traceback.format_tb(exceptionTraceback))) # print("*** tb_lineno:", traceback.tb_lineno(exceptionTraceback)) GPIO.cleanup() ###End Main

if __name__ == "__main__": main() ##Create main.py and declare import library## Define Reboot / Shutdown Call##Define Key Event##Define Main and register Key## Create Device object for display## Load Prepared Screen class## Loop all screen to display result###End Main





Create Screen Base Class from PIL import ImageFont class ScreenBase: def __init__(self): self.x = 0 self.top = 0 self.font = ImageFont.load_default() self.fontbig = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", 18) self.fontsuperbig = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", 25) self.temp = "" self.temp_new = "" def draw(self, x, top, width, height, line, panel, device, fill): raise NotImplementedError("Should have implemented this") def getSleepTime(self): raise NotImplementedError("Should have implemented this") def getSleepCount(self): raise NotImplementedError("Should have implemented this") def startThread(self): pass def next(self): pass Create System Screen from ScreenBase import * import subprocess class SystemScreen(ScreenBase): def draw(self, x, top, width, height, line, panel, device, fill): ##panel.rectangle(device.bounding_box, outline="white", fill="black") cmd = "hostname -I" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) IP = ps.communicate()[0].decode('utf-8').strip() cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) CPU = ps.communicate()[0].decode('utf-8').strip() cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %.2f%%\", $3,$2,$3*100/$2 }'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) MemUsage = ps.communicate()[0].decode('utf-8').strip() cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%dGB %s\", $3,$2,$5}'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) Disk = ps.communicate()[0].decode('utf-8').strip() cmd = """/sbin/ifconfig wlan0 | grep "RX packets" | awk '{print $6" " $7}' | sed 's/[()]//g'""" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) network_rx = ps.communicate()[0].decode('utf-8').strip() # print("network_rx "+network_rx ) cmd = """/sbin/ifconfig wlan0 | grep "TX packets" | awk '{print $6" " $7}' | sed 's/[()]//g'""" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) network_tx = ps.communicate()[0].decode('utf-8').strip() # print("network_tx " + network_tx) cmd = "date '+%Y-%m-%d %H:%M:%S'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) date_time = ps.communicate()[0].decode('utf-8').strip() cmd = "vcgencmd measure_temp | sed 's/temp=//g'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) temp = ps.communicate()[0].decode('utf-8').strip() cmd = "vcgencmd measure_volts | sed 's/volt=//g'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) volts = ps.communicate()[0].decode('utf-8').strip() panel.text((x, top), str(IP), font=self.font, fill=fill) panel.text((x, top + line), str(CPU), font=self.font, fill=fill) panel.text((x, top + (line * 2)), str(MemUsage), font=self.font, fill=fill) panel.text((x, top + (line * 3)), str(Disk), font=self.font, fill=fill) panel.text((x, top + (line * 4)), str(network_rx) + "/" + str(network_tx), font=self.font, fill=fill) panel.text((x, top + (line * 5)), str(temp) + "/" + str(volts), font=self.font, fill=fill) panel.text((x, top + (line * 6)), str(date_time), font=self.font, fill=fill) def getSleepTime(self): return 1 def getSleepCount(self): return 5 def startThread(self): print("Not implemented")



Create Current Time Screen from ScreenBase import * import subprocess class TimeScreen(ScreenBase): def draw(self, x, top, width, height, line, panel, device, fill): cmd = "date '+%Y-%m-%d %H:%M:%S'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) date_time = ps.communicate()[0].decode('utf-8').strip() datesize = panel.textsize(str(date_time).split(" ")[0]); # draw.font = fontsuperbig timesize = panel.textsize(str(date_time).split(" ")[1]); panel.text((x + (width / 2) - timesize[0], top + (height / 2) - timesize[1]), str(date_time).split(" ")[1], font=self.fontsuperbig, fill=fill) panel.text((x + (width / 2) - timesize[0] + 2, top + (height / 2) + timesize[1] + 5), str(date_time).split(" ")[0], font=self.fontbig, fill=fill) def getSleepTime(self): return 1 def getSleepCount(self): return 5 def startThread(self): print("Not implemented")





Test your main now Remote login to your Pi Zero now and run the command below

python3 main.py



Your should see the following screen which indicate your python call is connected to OLED display successfully





How to show your Admob Summary in the OLED Display? First of all download the sample project and test your setting in the sample

https://github.com/googleads/googleads-adsense-examples/tree/master/python/v1.4



Once you have tested and generated your own Account ID, try to access your Admob Account



Create your own python class to access the summary of today ##Create file and name it as admob_today.py

You may need to change the timezone from Hong Kong to other/system default



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 import datetime from pytz import timezone import argparse import sys from adsense_util import get_account_id from adsense_util_data_collator import DataCollator from apiclient import sample_tools from oauth2client import client # Declare command-line flags. argparser = argparse.ArgumentParser(add_help=False) argparser.add_argument( '--report_id' , help= 'The ID of the saved report to generate' ) def main(argv): # Authenticate and construct service. service, flags = sample_tools.init( argv, 'adsense' , 'v1.4' , __doc__, __file__, parents=[argparser], scope= 'https://www.googleapis.com/auth/adsense.readonly' ) # Process flags and read their values. saved_report_id = flags.report_id now_pacific = datetime.datetime.now(timezone( 'Asia/Hong_Kong' )) + datetime.timedelta(days= 1 ) today_pacific = now_pacific.strftime( '%Y-%m-%d' ) yesterday_pacific = datetime.datetime.now(timezone( 'Asia/Hong_Kong' )) yesterday_pacific = yesterday_pacific.strftime( '%Y-%m-%d' ) ##print (" today_pacific " , today_pacific) ##print ("yesterday_pacific " , yesterday_pacific) try : # Let the user pick account if more than one. account_id = get_account_id(service) # Retrieve report if saved_report_id: result = service.accounts().reports().saved().generate( accountId=account_id, savedReportId=saved_report_id).execute() else : result = service.accounts().reports().generate( accountId=account_id, startDate=yesterday_pacific, endDate=today_pacific, metric=[ 'PAGE_VIEWS' , 'CLICKS' , 'COST_PER_CLICK' , 'EARNINGS' ], dimension=[ 'MONTH' ], sort=[ '+MONTH' ], useTimezoneReporting=True).execute() result = DataCollator([result]).collate_data() # Display headers. for header in result[ 'headers' ]: print ( '%25s' % header[ 'name' ]), ##print print # Display results. for row in result[ 'rows' ]: for column in row: print ( '%25s' % column), print # Display date range. ##print 'Report from %s to %s.' % (result['startDate'], result['endDate']) ##print except client.AccessTokenRefreshError: print ( 'The credentials have been revoked or expired, please re-run the ' 'application to re-authorize' ) if __name__ == '__main__' : main(sys.argv)

##Test it by python admob_today.py



Create a new Screen to display your summary

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from ScreenBase import * import subprocess class AdmobTodayScreen(ScreenBase): def __init__(self): self.count = 0 super(AdmobTodayScreen, self).__init__() def draw(self, x, top, width, height, line, panel, device, fill): try : cmd = "python admob_today.py | grep -v MONTH | awk '{ print $1\"=\"$2\"=\"$3\"=\"$4\"=\"$5}'" ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = ps.communicate()[ 0 ].decode( 'utf-8' ).strip() if (len(result) <= 0 or result == "" ): result = "0=0=0=0=0" if (self.count % 3 == 0 ): text = "$" +str(result).split( "=" )[ 4 ] panel.text((x, top), "Today Earn" , font=self.fontsuperbig, fill=fill) panel.text((width - self.fontsuperbig.getsize(text)[ 0 ] - 2 , top + 26 ), text, font=self.fontsuperbig, fill=fill) if (self.count % 3 == 1 ): text = str(result).split( "=" )[ 2 ] + " / $" + str(result).split( "=" )[ 3 ] panel.text((x, top), "T Clicks" , font=self.fontsuperbig, fill=fill) panel.text((width - self.fontsuperbig.getsize(text)[ 0 ] - 2 , top + 26 ), text, font=self.fontsuperbig, fill=fill) if (self.count % 3 == 2 ): text = str(result).split( "=" )[ 1 ] panel.text((x, top), "T Views" , font=self.fontsuperbig, fill=fill) panel.text((width - self.fontsuperbig.getsize(text)[ 0 ] - 2 , top + 26 ), text, font=self.fontsuperbig, fill=fill) except : print ( "Error when AdmobTodayScreen" ) def getSleepTime(self): return 3 def getSleepCount(self): return 3 * 5 def startThread(self): print ( "Not implemented" ) def next(self): self.count = self.count + 1

Include the new Screen into main.py

from AdmobTodayScreen import * screenList = [SystemScreen(), loadingScreen, TimeScreen(), loadingScreen, AdmobTodayScreen() ]





##Run the python3 main.py again, eventually your will see the following result









Similar project in E-ink











Remote login to your Pi Zero now and run the command belowpython3 main.pyYour should see the following screen which indicate your python call is connected to OLED display successfullyFirst of all download the sample project and test your setting in the sampleOnce you have tested and generated your own Account ID, try to access your Admob Account##Create file and name it as admob_today.pyYou may need to change the timezone from Hong Kong to other/system default##Test it by python admob_today.pyInclude the new Screen into main.py##Run the python3 main.py again, eventually your will see the following result



