Status Display

If you attach a type SSD1306 128×64 OLED display to the i2c pins on your TimePi, you can use this script to display the current system status.

| TimePi_OLED.py
#! /usr/bin/python
# John Miller 2022-03-28
# Combined from: https://learn.adafruit.com/adafruit-pioled-128x32-mini-oled-for-raspberry-pi/usage
#           and: http://www.danmandle.com/blog/getting-gpsd-to-work-with-python/
 
 
import os
from gps import *
from time import *
import threading
import subprocess
 
from board import SCL, SDA
import busio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
 
 
gpsd = None #seting the global variable
 
# Create the I2C interface.
i2c = busio.I2C(SCL, SDA)
 
# create display class
disp = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
 
# 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.rectangle((0, 0, width, height), outline=0, fill=0)
padding = -2
top = padding
bottom = height - padding
x = 0
 
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 11)
 
 
class GpsPoller(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    global gpsd #bring it in scope
    gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
    self.current_value = None
    self.running = True #setting the thread running to true
 
  def run(self):
    global gpsd
    while gpsp.running:
      gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
 
if __name__ == '__main__':
  gpsp = GpsPoller() # create the thread
  try:
    gpsp.start() # start it up
    while True:
      # It may take a second or two to get good data
      # print(gpsd.fix.latitude,', ',gpsd.fix.longitude,'  Time: ',gpsd.utc)
 
      os.system('clear')
 
      # clear LCD
      draw.rectangle((0, 0, width, height), outline=0, fill=0)
 
      ipv4 = os.popen('ip addr show eth0 | grep "\<inet\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
      load = os.popen("cat /proc/loadavg | awk '{print $1 \", \" $2 \", \" $3}'").read()[:-1]
      days = os.popen("expr `cat /proc/uptime | cut -d '.' -f1` % 31556926 / 86400").read()[:-1]
      hours = os.popen("expr `cat /proc/uptime | cut -d '.' -f1` % 31556926 % 86400 / 3600").read()[:-1]
      minutes = os.popen("expr `cat /proc/uptime | cut -d '.' -f1` % 31556926 % 86400 % 3600 / 60").read()[:-1]
 
      cputemp = os.popen("sensors | grep temp1 | awk '{print substr($2,2);}' | sed -n '2p'").read()[:-1]
      rtctemp = os.popen("sensors | grep temp1 | awk '{print substr($2,2);}' | sed -n '1p'").read()[:-1]
 
      date = os.popen("date +%Y-%m-%d").read()[:-1]
      time = os.popen("date -u +'%T %Z'").read()[:-1]
      reference = os.popen("chronyc tracking | sed -n 1p | awk '{print $5}' | tr -d '(),'").read()[:-1]
      stratum = os.popen("chronyc tracking | sed -n 2p | awk '{print $3}'").read()[:-1]
      jitter = os.popen("chronyc sources | sed -n 3p | awk '{print $10}'").read()[:-1]
 
      statusdict = {0: 'Unknown', 1: 'GPS', 2: 'DGPS', 3: 'RTK', 4: 'RTK FLT', 5: 'DR', 6: 'GNSSDR', 7: 'Surveyed', 8: 'SIM', 9: 'PPS'}
      fixdict = {1: 'No Fix', 2: '2D', 3: '3D'}
 
      draw.text((x, top + 0), "==== SYSTEM ====", font=font, fill=255)
      draw.text((x, top + 12), "IP: " + ipv4, font=font, fill=255)
      draw.text((x, top + 22), "Load: " + load, font=font, fill=255)
      draw.text((x, top + 32), "CPU Temp: " + cputemp, font=font, fill=255)
      draw.text((x, top + 42), "RTC Temp: " + rtctemp, font=font, fill=255)
      draw.text((x, top + 52), "Uptime: " + days + "D " + hours + "H " + minutes + "M", font=font, fill=255)
      disp.image(image)
      disp.show()
 
      sleep(5)
 
      draw.rectangle((0, 0, width, height), outline=0, fill=0)
      draw.text((x, top + 0), "===== GNSS =====", font=font, fill=255)
      draw.text((x, top + 12), "Seen: " + str(len(gpsd.satellites)) + " Used: " + str(gpsd.satellites_used), font=font, fill=255)
      draw.text((x, top + 22), "Fix Type: " + fixdict.get(gpsd.fix.mode), font=font, fill=255)
      draw.text((x, top + 32), "Status: " + statusdict.get(gpsd.fix.status), font=font, fill=255)
      draw.text((x, top + 42), "TDOP: " + str(gpsd.tdop), font=font, fill=255)
      draw.text((x, top + 52), "PDOP: " + str(gpsd.pdop), font=font, fill=255)
      disp.image(image)
      disp.show()
 
      sleep(5) #set to whatever
 
      draw.rectangle((0, 0, width, height), outline=0, fill=0)
      draw.text((x, top + 0), "==== CHRONY ====", font=font, fill=255)
      draw.text((x, top + 12), "Date: " + date, font=font, fill=255)
      draw.text((x, top + 22), "Time: " + time, font=font, fill=255)
      draw.text((x, top + 32), "Reference: " + reference, font=font, fill=255)
      draw.text((x, top + 42), "Stratum: " + stratum, font=font, fill=255)
      draw.text((x, top + 52), "PPS Jitter: " + jitter, font=font, fill=255)
      disp.image(image)
      disp.show()
 
      sleep(5)
 
  except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
    print("\nKilling Thread...")
    gpsp.running = False
    gpsp.join() # wait for the thread to finish what it's doing
    # clear screen
    draw.rectangle((0, 0, width, height), outline=0, fill=0)
    disp.image(image)
    disp.show()  
  print("Done.\nExiting.")