A Raspberry Pi-based clock with GPS time synchronization and weather display using a 7-segment LED display. This project combines accurate GPS timekeeping with local weather information for a comprehensive desktop clock solution.
- GPS Time Synchronization: Uses Adafruit Ultimate GPS HAT for precise timekeeping
- Weather Display: Shows current temperature, feels-like temperature, and humidity
- 7-Segment Display: Clean, readable LED display with scrolling text
- Custom Text Display: Configurable custom messages that scroll across the display at set intervals
- Configurable: Customizable time format, temperature units, display cycles, and custom text
- Modular Design: Easy to assemble and modify with plug-and-play connections
-
Raspberry Pi Zero 2 W (or any Raspberry Pi with 40-pin GPIO header)
-
Adafruit Ultimate GPS HAT for Raspberry Pi - Mini Kit
-
Adafruit 1.2" 4-Digit 7-Segment Display w/I2C Backpack
-
GPIO Stacking Header for Pi A+/B+/Pi 2/Pi 3 - Extra-long 2x20 Pins
-
CR1220 Coin Cell Battery (for GPS HAT RTC backup)
-
Female-to-Female Dupont Jumper Wires (5 wires minimum: VIN, IO, GND, SDA, SCL)
-
SMA to uFL/u.FL/IPX/IPEX RF Adapter Cable (optional, for external antenna)
-
External GPS Antenna with SMA connector (optional, improves indoor reception)
- Micro-USB OTG Adapter (for future Meshtastic integration)
- Project Enclosure (for permanent installation)
- Heat Shrink Tubing (for cable management)
-
Clone Repository:
git clone https://github.com/jkeychan/rpi-clock.git cd rpi-clock -
Run Automated Setup:
./setup.sh
-
Configure Settings: Edit
config.iniwith your OpenWeatherMap API key and ZIP code:sudo nano /opt/rpi-clock/config.ini
-
Reboot (if prompted by setup script)
-
Verify Installation: Check GPS and display are working:
# Test GPS connection cgps -s # Check chrony sources chronyc sources # Check clock service sudo systemctl status rpi-clock
If you prefer manual setup over the automated script:
- Assemble Hardware: Follow the Hardware Setup Guide below
- Configure Raspberry Pi: Complete the System Configuration steps
- Install Dependencies: Run the Software Installation commands
- Configure GPS Time Sync: Set up GPS Time Synchronization
- Update Configuration: Edit
config.iniwith your settings - Run the Clock: Execute
python3 clock.py
- Solder Stacking Header: Instead of the standard header, solder the extra-long stacking header to the GPS HAT
- Insert Battery: Place the CR1220 coin cell battery in the GPS HAT's battery holder
- Stack HAT: Connect the GPS HAT to your Raspberry Pi's GPIO header
-
Add Pins to Display: Solder the 5 pin headers that came with the display to the back with the longer ends pointing towards the back.
-
Connect Female Dupont Connectors to Display: Connect the female Dupont wires to the 7-segment display backpack:
- Red → VIN (5V power)
- Orange → IO (3.3V logic)
- Black → GND (ground)
- Yellow → SDA (data)
- White → SCL (clock)
-
Connect to the Raspberry Pi: Plug the Dupont connectors to the stacking header pins:
- Red → VIN → Pi 5V pin 2
- Orange → IO → Pi 3.3V pin 1
- Black → GND → Pi GND pin 6
- Yellow → SDA → Pi SDA (GPIO 2) pin 3
- White → SCL → Pi SCL (GPIO 3) pin 5
- Connect the SMA to uFL adapter cable to the GPS HAT
- Attach an external GPS antenna with SMA connector
- Position antenna for optimal satellite reception
Use these commands to automatically enable I2C and configure the GPS HAT:
# Enable I2C interface
sudo raspi-config nonint do_i2c 0
# Configure serial port (disable login shell, enable hardware)
sudo raspi-config nonint do_serial 1
# Enable UART for GPS HAT
sudo sed -i 's/enable_uart=0/enable_uart=1/' /boot/firmware/config.txt
# Disable Bluetooth to free UART for GPS HAT
sudo sed -i '/enable_uart=1/a dtoverlay=disable-bt' /boot/firmware/config.txt
# Install I2C tools
sudo apt install -y i2c-tools
# Add user to i2c group (no need to logout/login)
sudo usermod -a -G i2c $USER
# Reboot to apply changes
sudo reboot-
Open Raspberry Pi Configuration:
sudo raspi-config
-
Enable I2C (for display):
- Navigate to
Interface Options>I2C - Select
Yesto enable I2C
- Navigate to
-
Configure Serial Port (for GPS):
- Navigate to
Interface Options>Serial Port - Select
Nofor login shell over serial - Select
Yesto enable serial port hardware
- Navigate to
-
Configure GPS HAT (manual step):
# Enable UART for GPS HAT sudo sed -i 's/enable_uart=0/enable_uart=1/' /boot/firmware/config.txt # Disable Bluetooth to free UART for GPS HAT sudo sed -i '/enable_uart=1/a dtoverlay=disable-bt' /boot/firmware/config.txt
-
Reboot:
sudo reboot
You can also manually edit the configuration files:
# Enable I2C by adding to /boot/firmware/config.txt
echo "dtparam=i2c_arm=on" | sudo tee -a /boot/firmware/config.txt
# Disable serial console login and enable hardware
sudo sed -i 's/console=serial0,115200//' /boot/firmware/cmdline.txt
# Enable UART for GPS HAT
echo "enable_uart=1" | sudo tee -a /boot/firmware/config.txt
# Disable Bluetooth to free UART for GPS HAT
echo "dtoverlay=disable-bt" | sudo tee -a /boot/firmware/config.txt
# Install I2C tools and add user to group
sudo apt install -y i2c-tools
sudo usermod -a -G i2c $USER
# Reboot
sudo rebootAfter enabling I2C and rebooting, verify the setup is working:
-
Check I2C Kernel Module:
lsmod | grep i2cYou should see
i2c_devandi2c_bcm2835modules loaded. -
Install I2C Tools (if not already installed):
sudo apt install i2c-tools
-
Detect I2C Devices:
sudo i2cdetect -y 1
You should see a device at address
70(the default address for the 7-segment display). If you seeUUinstead of70, the device is in use by another process. -
Check I2C Bus Status:
sudo i2cdetect -l
Should show
i2c-1bus available. -
Test Display Communication:
python3 -c " import board import busio i2c = busio.I2C(board.SCL, board.SDA) print('I2C devices found:', [hex(addr) for addr in i2c.scan()]) "
Should print
['0x70']if the display is connected properly.
After enabling UART and disabling Bluetooth, verify the GPS HAT is detected:
-
Check GPS HAT Device:
ls -la /dev/ttyAMA*You should see
/dev/ttyAMA0if the GPS HAT is properly connected. -
Check I2C Detection:
sudo i2cdetect -y 1
You should see a device at address
70(GPS HAT I2C interface). -
Test GPS Connection:
# Install GPS tools sudo apt install gpsd gpsd-clients # Test GPS data reception with PPS auto-detection sudo gpsd -N -n /dev/ttyAMA0 timeout 10 gpspipe -r | head -5
Should show GPS data if antenna has clear sky view. PPS will be auto-detected if available for microsecond precision timing.
-
Check GPS Status:
cgps -s
Shows GPS fix status and satellite information.
The GPS HAT requires UART access and Bluetooth must be disabled to free the UART interface:
-
UART and Bluetooth Configuration (already configured in automated setup):
# Enable UART for GPS HAT sudo sed -i 's/enable_uart=0/enable_uart=1/' /boot/firmware/config.txt # Disable Bluetooth to free UART for GPS HAT sudo sed -i '/enable_uart=1/a dtoverlay=disable-bt' /boot/firmware/config.txt
-
Reboot:
sudo reboot
-
Verify GPS HAT Detection:
# Check GPS HAT device ls -la /dev/ttyAMA* # Check PPS device (precision timing) ls -la /dev/pps*
Should show
/dev/ttyAMA0and/dev/pps0available for GPS HAT. PPS provides microsecond precision timing for chrony.
# Update package list
sudo apt update
# Install Python package manager
sudo apt install python3-pip
# Install required Python packages
pip3 install --break-system-packages adafruit-circuitpython-ht16k33 requests ntplib
# Install GPS daemon and clients
sudo apt install gpsd gpsd-clients
# Install time synchronization software
sudo apt install chronyNote: On newer Debian/Ubuntu systems, you may encounter an "externally managed environment" error. The setup script handles this automatically with the --break-system-packages flag.
The setup script also installs development tools for code quality:
# Install Python development tools
pip3 install --user flake8
# Install shellcheck for bash script validation
sudo apt install shellcheck-
Disable Default Service:
sudo systemctl stop gpsd.socket sudo systemctl disable gpsd.socket
-
Start gpsd Manually:
sudo gpsd /dev/serial0 -F /var/run/gpsd.sock
-
Test GPS Connection:
cgps -s
Look for "3D fix" status indicating successful GPS lock.
Chrony provides faster synchronization and better performance. The setup script automatically installs an optimized configuration that:
- Uses GPS as primary time source
- Serves time to all networks (public time server)
- Includes upstream NTP servers for backup
- Optimized for Raspberry Pi performance
Manual Configuration (if needed):
-
Configure Chrony:
sudo nano /etc/chrony/chrony.conf
-
Use Provided Configuration: The setup script installs
chrony.confwith optimized settings for GPS time serving. -
Restart Chrony:
sudo systemctl restart chrony
-
Verify Synchronization:
chronyc sources
Look for GPS source marked with asterisk (*).
Public Time Server Features:
- Serves time to all networks (
allow 0.0.0.0/0) - GPS + PPS reference clocks for maximum accuracy
- Upstream NTP servers for backup synchronization
- Optimized polling intervals for GPS sources
Verify Public Time Serving:
# Check chrony sources
chronyc sources
# Check chrony tracking
chronyc tracking
# Test from another machine
ntpdate -q your.pi.ip.address
# Check if port 123 is open
netstat -ulnp | grep :123If you prefer traditional NTP:
-
Install NTP:
sudo apt install ntp
-
Configure NTP:
sudo nano /etc/ntp.conf
-
Add GPS Reference: Add these lines:
# GPS reference clock server 127.127.28.0 minpoll 4 maxpoll 4 fudge 127.127.28.0 time1 0.420 refid GPS -
Restart NTP:
sudo systemctl restart ntp
Edit the config.ini file with your settings. The application validates the configuration on startup and provides clear error messages for any issues:
[Weather]
api_key = your_openweathermap_api_key_here
zip_code = your_zip_code_here
[Display]
time_format = 24
temp_unit = F
[NTP]
preferred_server = 127.0.0.1
[Cycle]
time_display = 2
temp_display = 2
feels_like_display = 2
humidity_display = 2
[CustomText]
enabled = true
text = WART 95.5 FM
interval_minutes = 15
display_duration = 3- time_format:
12for 12-hour format,24for 24-hour format - temp_unit:
Cfor Celsius,Ffor Fahrenheit - smooth_scroll:
truefor stock-ticker style scrolling (affects both weather and custom text),falsefor static display - preferred_server:
127.0.0.1for local GPS time, or external NTP server - Cycle settings: Display duration in seconds for each metric (1-60 seconds)
- CustomText settings:
- enabled:
trueto enable custom text display,falseto disable - text: Custom message to display (max 50 characters recommended)
- interval_minutes: How often to show custom text (1-1440 minutes, i.e., 1 minute to 24 hours)
- display_duration: How long to display custom text (1-60 seconds)
- enabled:
The application validates configuration on startup:
- Checks for required sections and options
- Validates API key format and ZIP code format
- Ensures display settings are valid
- Verifies cycle durations are within acceptable range
- Validates custom text settings when enabled
- Provides clear error messages for any issues
python3 clock.pyThe setup script automatically creates a systemd service for auto-start. The clock files are installed to /opt/rpi-clock/ and the service runs as your user.
Manual Service Management:
# Start the service
sudo systemctl start rpi-clock.service
# Stop the service
sudo systemctl stop rpi-clock.service
# Check service status
sudo systemctl status rpi-clock.service
# View service logs
sudo journalctl -u rpi-clock.service -fConfiguration Updates: After installation, edit the configuration file:
sudo nano /opt/rpi-clock/config.ini
sudo systemctl restart rpi-clock.serviceThe project includes three essential diagnostic scripts to help troubleshoot issues:
# Test I2C display connection
./i2c-test.sh
# Test GPS connection and synchronization
./gps-test.sh
# Test NTP time synchronization
./ntp-test.shThese scripts are installed to /opt/rpi-clock/ and can be run from there. Each script provides comprehensive diagnostics and troubleshooting suggestions for its specific component.
- No GPS Fix: Ensure antenna has clear view of sky
- Slow Fix: Wait 5-10 minutes for cold start
- Poor Signal: Use external antenna for indoor use
- No Display: Check I2C connections and enable I2C interface
- Wrong Characters: Verify SDA/SCL connections
- Dim Display: Check power connections
If your display isn't working, follow these steps:
-
Verify I2C is Enabled:
# Check if I2C modules are loaded lsmod | grep i2c # Check if I2C device exists ls /dev/i2c*
-
Check Physical Connections:
- Ensure VIN (red) is connected to Pi pin 2 (5V)
- Ensure IO (orange) is connected to Pi pin 1 (3.3V) - REQUIRED
- Ensure GND (black) is connected to Pi pin 6 (GND)
- Ensure SDA (yellow) is connected to Pi pin 3 (GPIO 2)
- Ensure SCL (white) is connected to Pi pin 5 (GPIO 3)
-
Test I2C Communication:
# Install i2c-tools if not already installed sudo apt install i2c-tools # Scan for I2C devices sudo i2cdetect -y 1
Expected output should show
70at the intersection of row 7, column 0. -
Check for Address Conflicts:
# If you see UU instead of 70, the device is in use sudo i2cdetect -y 1If you see
UUat address 70, another process is using the display. -
Test Python I2C Access:
python3 -c " try: import board import busio i2c = busio.I2C(board.SCL, board.SDA) devices = i2c.scan() print('I2C devices found:', [hex(addr) for addr in devices]) if 0x70 in devices: print('Display found at address 0x70') else: print('Display NOT found - check connections') except Exception as e: print('I2C error:', e) "
-
Common Solutions:
- No devices found: Check power and ground connections, ensure both 5V (VIN) and 3.3V (IO) are connected
- Permission denied: Add user to i2c group:
sudo usermod -a -G i2c $USERthen logout/login - Device busy: Stop any running clock processes:
sudo systemctl stop rpi-clock.service - Wrong address: Some displays may use address 0x71 instead of 0x70
- Missing 3.3V: The display requires both 5V (VIN) and 3.3V (IO) connections to function
- Wrong Time: Verify GPS fix and chrony/ntp status
- Drift: Check GPS antenna placement
- No Sync: Restart gpsd and chrony services
- No Weather: Check internet connection and API key
- Wrong Location: Verify ZIP code in config.ini
Use the provided uninstall script:
./uninstall.shTo remove the RPI-Clock installation manually:
# Stop and disable the service
sudo systemctl stop rpi-clock.service
sudo systemctl disable rpi-clock.service
# Remove the service file
sudo rm /etc/systemd/system/rpi-clock.service
# Remove installed files
sudo rm -rf /opt/rpi-clock
# Reload systemd
sudo systemctl daemon-reload
# Optional: Remove dependencies (be careful if other projects use them)
# sudo apt remove gpsd gpsd-clients chrony
# pip3 uninstall adafruit-circuitpython-ht16k33 requests configparser ntplib- Meshtastic Integration: Add LoRa mesh networking capabilities
- Multiple Displays: Support for additional 7-segment displays
- Web Interface: Remote configuration and monitoring
- Data Logging: Historical weather and time data
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

