#!/usr/bin/python3 # 2024 -- bt www.LostGeek.NET # This runs the clock on an i2c 20x4 LCD display; run via cron with @reboot to auto-start. # This version uses two rows for "big digits" clock; bottom two for weather/stats from RPLCD.i2c import CharLCD from time import sleep, time from datetime import datetime import requests # Initialize the LCD (modify address if necessary) lcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=1, cols=20, rows=4, dotsize=8) # Define custom characters for big digits top_line = (0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000) bottom_line = (0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111) both_lines = (0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111) lcd.create_char(0, top_line) lcd.create_char(1, bottom_line) lcd.create_char(2, both_lines) big_digit_map = { "0": [(255, 0, 255), (255, 1, 255)], # "0" uses custom characters 3 and 4 "1": [(0, 255, 254), (1, 255, 1)], "2": [(2, 2, 255), (255, 1, 1)], "3": [(0, 2, 255), (1, 1, 255)], "4": [(255, 1, 255), (254, 254, 255)], "5": [(255, 2, 2), (1, 1, 255)], "6": [(255, 2, 2), (255, 1, 255)], "7": [(0, 0, 255), (254, 254, 255)], "8": [(255, 2, 255), (255, 1, 255)], "9": [(255, 2, 255), (1, 1, 255)] } # Function to display a big digit at a given position def disp_number(number, position): if number in big_digit_map: # Clear previous digit lcd.cursor_pos = (0, position) lcd.write_string(" ") lcd.cursor_pos = (1, position) lcd.write_string(" ") # Write new digit lcd.cursor_pos = (0, position) for char in big_digit_map[number][0]: lcd.write_string(chr(char)) lcd.cursor_pos = (1, position) for char in big_digit_map[number][1]: lcd.write_string(chr(char)) # Function to fetch text from the URL def fetch_text(): try: response = requests.get("http://ben.lostgeek.net/wclock.txt", timeout=5) # You'll want to use your own! response.raise_for_status() lines = response.text.strip().split("\n") return lines[:3] if len(lines) >= 3 else [" "] * 3 except: return ["Error", "Server", "Conn."] # Main loop old_time = "" last_fetch_time = 0 text_lines = [" ", " ", " "] text_toggle = False while True: now = datetime.now() new_time = now.strftime('%H%M') seconds = now.strftime('%S') current_time = time() # Fetch new text every 10 minutes if current_time - last_fetch_time >= 600: text_lines = fetch_text() last_fetch_time = current_time # Only update time if it has changed if new_time != old_time: old_time = new_time digits = str(new_time) disp_number(digits[0], 1) # Shift HH left by one space disp_number(digits[1], 5) # Adjust HH disp_number(digits[2], 12) # Shift MM right by one space disp_number(digits[3], 16) # Adjust MM # Update seconds display lcd.cursor_pos = (0, 9) lcd.write_string(seconds) # Update third and fourth rows lcd.cursor_pos = (2, 0) lcd.write_string(text_lines[0].ljust(20)) lcd.cursor_pos = (3, 0) lcd.write_string(text_lines[1 if text_toggle else 2].ljust(20)) # Toggle text every 4 seconds if int(seconds) % 4 == 0: text_toggle = not text_toggle sleep(1)