Clock and Temperature display
Using an ILI9341 SPI display with a DS18B20 Temperature sensor connected to a Raspberry PI Zero.
I did a search on Youtube and found a starting point. The script I found had me running in just a few minutes. I made some modifications and posted that below. Hopefully this helps someone.
I'm using a SunFounder DS18B20 to get the temperature in the room. I only want an accurate time source with the temperature. Using a Pi Zero with NTP and the temperature sensor is all I need. To display the data, I found a 2.2 inch ILI9341. I hope to get this into a case more suitable for a desktop.
To get the DS18B20 connected, I followed the instructions from the vendor: https://www.sunfounder.com/learn/sensor-kit-v2-0-for-raspberry-pi-b-plus/lesson-26-ds18b20-temperature-sensor-sensor-kit-v2-0-for-b-plus.html
I'm using a SunFounder DS18B20 to get the temperature in the room. I only want an accurate time source with the temperature. Using a Pi Zero with NTP and the temperature sensor is all I need. To display the data, I found a 2.2 inch ILI9341. I hope to get this into a case more suitable for a desktop.
To get the DS18B20 connected, I followed the instructions from the vendor: https://www.sunfounder.com/learn/sensor-kit-v2-0-for-raspberry-pi-b-plus/lesson-26-ds18b20-temperature-sensor-sensor-kit-v2-0-for-b-plus.html
To get the display connected and setup the modules, I did a couple of searches on the web and used this one: https://pi0cket.com/ili9341-raspberry-pi-guide/
My abbreviated config for the display is at the bottom of this post. I was running Stretch Lite when I originally wrote this article. For Buster Lite on a Pi display, I have those steps abbreviated at the bottom of this post.
<---- ILI9341 Pin to Raspberry PI Zero Pin ---->
My abbreviated config for the display is at the bottom of this post. I was running Stretch Lite when I originally wrote this article. For Buster Lite on a Pi display, I have those steps abbreviated at the bottom of this post.
![]() |
| Clock based on first script below |
![]() |
| The three connections on the left are the temperature sensor. From the grey wire to the right are the 9 connectors for the display |
![]() |
| The other side of the Pi Zero to show those connections |
![]() |
| The ILI9341 connections |
![]() |
| SunFounder DS18B20 |
| Raspberry PI Pinout |
<---- ILI9341 Pin to Raspberry PI Zero Pin ---->
SDO/MISO ---- 21 (GPIO9) LED ---- 12 (GPIO18) SCK ---- 23 (GPIO11) SDI/MOSI ---- 19 (GPIO10) DC/RS ---- 18 (GPIO24) RESET ---- 22 (GPIO25) CS ---- 24 (GPIO8) GND ---- 20 (GND) VCC ---- 17 (3v3)
<---- Sunfounder DS18B20 Sensor Pin to Raspberry PI Zero Pin ---->
SIG (1) ---- 7 (GPIO4) VCC (2) ---- 2 (5v) GND (3) ---- 6 (GND)
<---- Begin Code Section for myclock.py ---->
#!/usr/bin/python
#----------------------------------------------------------------
# Note:
# ds18b20's data pin must be connected to pin7.
# replace the 28-XXXXXXXXX as yours.
#----------------------------------------------------------------
import pygame, sys, os, time, datetime, signal
from pygame.locals import *
os.environ["SDL_FBDEV"] = "/dev/fb1"
## Globals
pygame.init()
## Set up the screen
display_width = 320
display_height = 240
#display_width = 800
#display_height = 480
DISPLAYSURF = pygame.display.set_mode((display_width, display_height), 0, 16)
pygame.mouse.set_visible(0)
pygame.display.set_caption('Room Temp')
# set up the colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
COBALTGREEN = ( 61, 145, 64)
BLUE = ( 0, 0, 255)
CYAN = ( 0, 255, 255)
YELLOW = (255, 255, 0)
BANANA = (227,207,87)
GOLD1 = (255,215,0)
EMERALDGREEN = (0, 201, 87)
ALICEBLUE = (240,248,255)
ds18b20 = ''
def setup():
global ds18b20
for i in os.listdir('/sys/bus/w1/devices'):
if i != 'w1_bus_master1':
ds18b20 = i
def readTemp():
# location = '/sys/bus/w1/devices/28-00000a423922/w1_slave'
location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
tfile = open(location)
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
return temperature
def signal_handler (signal, frame):
pygame.quit()
sys.exit(0)
def DrawLine(color, startX,startY,stopX,stopY):
pygame.draw.line(DISPLAYSURF, color, [startX,startY], [stopX,stopY], 1)
## Start
signal.signal(signal.SIGINT, signal_handler)
setup()
## Main loop
while True:
currenttime = datetime.datetime.now()
if readTemp() != None:
currenttemp = readTemp()
temp_c = str("{0:.1f}".format(currenttemp))
temp_f = str("{0:.1f}".format((currenttemp*9/5)+32))
## Draw the title
black_square_that_is_the_size_of_the_screen = pygame.Surface(DISPLAYSURF.get_size())
black_square_that_is_the_size_of_the_screen.fill((0, 0, 0))
DISPLAYSURF.blit(black_square_that_is_the_size_of_the_screen, (0, 0))
font = pygame.font.Font(None, 30)
text = font.render("Room Temp", 1, EMERALDGREEN)
textpos = text.get_rect(center=(display_width*.5,int(round(.08*display_height))))
DISPLAYSURF.blit(text, textpos)
## Draw temperatures
font = pygame.font.Font(None, 70)
text = font.render(temp_f, 1, GOLD1)
textpos = text.get_rect(center=(display_width*.25,int(round(.30*display_height))))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "F", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 10
DISPLAYSURF.blit(textF, textposF)
font = pygame.font.Font(None, 70)
text = font.render(temp_c, 1, GOLD1)
textpos = text.get_rect(center=(display_width*.75,int(round(.30*display_height))))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "C", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 10
DISPLAYSURF.blit(textF, textposF)
## Draw date
font = pygame.font.Font(None, 40)
text = font.render(currenttime.strftime("%A, %b %d"), 1, ALICEBLUE)
textpos = text.get_rect(center=(display_width/2,int(round(.58*display_height))))
DISPLAYSURF.blit(text, textpos)
## Draw time
font = pygame.font.Font(None, 85)
text = font.render(currenttime.strftime("%I:%M %p"), 1, ALICEBLUE)
textpos = text.get_rect(center=(display_width/2,int(round(.79*display_height))))
DISPLAYSURF.blit(text, textpos)
## Draw Lines
DrawLine(EMERALDGREEN, 5, int(round(.16*display_height)), display_width-5, int(round(.16*display_height)))
DrawLine(EMERALDGREEN, 5, int(round(.45*display_height)), display_width-5, int(round(.45*display_height)))
DrawLine(EMERALDGREEN, display_width*.5, int(round(.16*display_height)), display_width*.5, int(round(.45*display_height)))
## Update the LCD
pygame.display.update()
## Sleep time!
time.sleep(15)
<---- End Code Section ---->
Abbreviated display configuration:
Assuming you have updated your install (apt update and apt upgrade) and have the DS18B20 connected and working, here are the steps I used based on the Pi0cket blog mentioned above. These steps will get the display running your script automatically on a reboot:
sudo rm /usr/bin/pythonsudo ln -s /usr/bin/python3 /usr/bin/pythonsudo apt install python3-pipsudo pip3 install pygame==1.9.6
2. SDL 1.2 gets installed using the following:
sudo apt-get install libsdl1.2-devsudo apt-get install libsdl-image1.2-dev
sudo apt-get install libsdl-ttf2.0-dev
one line to get all 3:sudo apt-get install -y libsdl1.2-dev libsdl-image1.2-dev libsdl-ttf2.0-dev
-Enable SPI (in raspi-config -> Interfacing Options -> P4 SPI -> Yes)-Disable Overscan (in raspi-config -> Advanced Options -> A2 Overscan -> No)-Exit raspi-config
4. Execute: sudo nano /etc/modules
at the bottom of file add:
spi-bcm2835fbtft_device
my file looks like this:
5. Execute: sudo nano /etc/modprobe.d/fbtft.conf
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
spi-bcm2835
fbtft_device
5. Execute: sudo nano /etc/modprobe.d/fbtft.conf
options fbtft_device name=fb_ili9341 gpios=reset:25,dc:24,led:18 speed=16000000 bgr=1 rotate=90 custom=1
my file has only one line and looks like this:
options fbtft_device name=fb_ili9341 gpios=reset:25,dc:24,led:18 speed=16000000 bgr=1 rotate=90 custom=1
6. Make the ILI9341 display show your content:
con2fbmap 1 1
7. If the display shows up, reboot.
sudo reboot
Execute: sudo nano /etc/rc.localadd: /home/pi/bin/myclock.ph &
my rc.local looks like this:
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
sudo python /home/pi/myclock.py &
exit 09. If you're feeling comfortable, reboot your pi.
sudo reboot
You should see the results of your python script after the reboot is completed.
Utilize OpenWeatherMap data
I cleaned up some of my earlier script above. I also added an API call to get some additional weather information using openweathermap.org data. You'll need to register with openweathermap. The basic weather information is free to access. I wrote a separate blog that discusses openweathermap a little more. If you only need that information, it's here. Below is the python script with the additional data.![]() |
| Shown with the added weather data |
#!/usr/bin/python
#----------------------------------------------------------------
# Note:
# ds18b20's data pin must be connected to pin7.
# replace the 28-XXXXXXXXX as yours.
#----------------------------------------------------------------
import pygame, sys, os, time, datetime, signal, requests
from pygame.locals import *
os.environ["SDL_FBDEV"] = "/dev/fb1"
## Globals
pygame.init()
## Set up the screen
display_width = 320
display_height = 240
display_center = int(display_width*.5)
display_rcenter = int(display_width*.75)
display_lcenter = int(display_width*.25)
DISPLAYSURF = pygame.display.set_mode((display_width, display_height), 0, 16)
pygame.mouse.set_visible(0)
pygame.display.set_caption('Room Temp')
# set up the colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
COBALTGREEN = ( 61, 145, 64)
BLUE = ( 0, 0, 255)
CYAN = ( 0, 255, 255)
YELLOW = (255, 255, 0)
BANANA = (227,207,87)
GOLD1 = (255,215,0)
EMERALDGREEN = (0, 201, 87)
ALICEBLUE = (240,248,255)
ROSYBROWN1 = (255,193,193)
ds18b20 = ''
def setup():
global ds18b20
for i in os.listdir('/sys/bus/w1/devices'):
if i != 'w1_bus_master1':
ds18b20 = i
def readTemp():
# location = '/sys/bus/w1/devices/28-00000a423922/w1_slave'
location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
tfile = open(location)
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
return temperature
def signal_handler (signal, frame):
pygame.quit()
sys.exit(0)
def DrawLine(color, startX,startY,stopX,stopY):
pygame.draw.line(DISPLAYSURF, color, [startX,startY], [stopX,stopY], 1)
def openweather():
api_key = "get your api key at openweathermap.org/api"
base_url = "https://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + 'id=5391959&appid=' + api_key
response = requests.get(complete_url)
if response.status_code != 200:
exit
return response.json()
## Start
signal.signal(signal.SIGINT, signal_handler)
setup()
## Main loop
while True:
currenttemp = readTemp()
temp_c = str("{0:.1f}".format(currenttemp))
temp_f = str("{0:.1f}".format((currenttemp*9/5)+32))
response = openweather()
outtemp = float((response['main']['temp']-273.15)*9/5+32)
feeltemp = float((response['main']['feels_like']-273.15)*9/5+32)
outtemp = str("{0:.1f}".format(outtemp))
feeltemp = str("{0:.1f}".format(feeltemp))
weather_desc = response['weather'][0]['description']
## Draw the title
blank_screen = pygame.Surface(DISPLAYSURF.get_size())
blank_screen.fill((0, 0, 0))
DISPLAYSURF.blit(blank_screen, (0, 0))
font = pygame.font.Font(None, 25)
text = font.render("Room", 1, EMERALDGREEN)
textpos = text.get_rect(center=(display_lcenter,16))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 25)
text = font.render("Outside/Feel", 1, EMERALDGREEN)
textpos = text.get_rect(center=(display_rcenter,16))
DISPLAYSURF.blit(text, textpos)
## Draw Lines
DrawLine(COBALTGREEN, 5, 28, display_width-5, 28)
DrawLine(COBALTGREEN, 5, 114, display_width-5, 114)
DrawLine(COBALTGREEN, display_center, 28, display_center, 114)
## Draw temperatures
font = pygame.font.Font(None, 70)
text = font.render(temp_f, 1, GOLD1)
textpos = text.get_rect(center=(display_lcenter,56))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "F", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 6
DISPLAYSURF.blit(textF, textposF)
font = pygame.font.Font(None, 50)
text = font.render(temp_c, 1, GOLD1)
textpos = text.get_rect(center=(display_lcenter,96))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "C", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 5
DISPLAYSURF.blit(textF, textposF)
font = pygame.font.Font(None, 70)
text = font.render(outtemp, 1, GOLD1)
textpos = text.get_rect(center=(display_rcenter,56))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "F", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 6
DISPLAYSURF.blit(textF, textposF)
font = pygame.font.Font(None, 50)
text = font.render(feeltemp, 1, GOLD1)
textpos = text.get_rect(center=(display_rcenter,96))
DISPLAYSURF.blit(text, textpos)
font = pygame.font.Font(None, 20)
textF = font.render(u'\u00b0' + "F", 1, GOLD1)
textposF = textpos[0] + textpos[2], textpos[1] + 5
DISPLAYSURF.blit(textF, textposF)
font = pygame.font.Font(None, 20)
text = font.render(weather_desc, 1, ROSYBROWN1)
textpos = text.get_rect(center=(display_rcenter,126))
DISPLAYSURF.blit(text, textpos)
## Draw time
currenttime = datetime.datetime.now()
font = pygame.font.Font(None, 85)
text = font.render(currenttime.strftime("%I:%M %p"), 1, WHITE)
textpos = text.get_rect(center=(display_center,180))
DISPLAYSURF.blit(text, textpos)
## Draw date
font = pygame.font.Font(None, 40)
text = font.render(currenttime.strftime("%A, %b %d"), 1, ALICEBLUE)
textpos = text.get_rect(center=(display_center,222))
DISPLAYSURF.blit(text, textpos)
## Update the LCD
pygame.display.update()
## Sleep time!
time.sleep(15) Abbreviated Buster Steps:buster lite with pi0 and ili9341
1. make sure you perform rpi-update to update to the latest firmware:
sudo rpi-update
2. sudo vi /boot/config.txt
- add to the end of the file:
dtoverlay=fbtft,ili9341,dc_pin=24,reset_pin=25dtparam=speed=16000000dtparam=custom=1dtparam=bgr=1dtparam=led_pin=18dtparam=rotate=90
3. I use python3 so make sure that is ready:sudo rm /usr/bin/pythonsudo ln -s /usr/bin/python3 /usr/bin/pythonsudo apt install python3-pipsudo pip3 install pygame==1.9.64. SDL 1.2 gets installed using the following:sudo apt-get install libsdl1.2-devsudo apt-get install libsdl-image1.2-dev
sudo apt-get install libsdl-ttf2.0-dev
If you read the earlier instructions for the Stretch version, you don't need the module setup that we did. You should be able to reboot the PI and see your display.
buster-lite with pi3b+ and 7 inch raspberry pi display
sudo vi /boot/config.txt
- add to the end of the file:lcd_rotate=2
reboot
sudo raspi-config
Under System Options, set the following for your needs:
S1 Wireless LANS4 HostnameS5 Boot / Auto Login
Under Display Options
D2 Underscan -> Yes to overscan
Interface Options
P2 SSH enable YesP7 1-Wire enable Yes
Configure Localization Options for your environment
L1 LocaleL2 TimezoneL3 Keyboard
Finish and reboot
Change the pi user passwordpasswd
Update and Install additional components:sudo apt updatesudo apt -y upgradesudo rm /usr/bin/pythonsudo ln -s /usr/bin/python3 /usr/bin/pythonsudo apt install -y python3-pipsudo apt install -y vimsudo pip3 install pygamesudo apt install -y libsdl2-2.0sudo apt install -y python3-sdl2
start the clock





