From 79c92c23aa4c97af512c2544a20f37482c62a577 Mon Sep 17 00:00:00 2001 From: jerick Date: Mon, 11 Aug 2025 20:11:32 -0400 Subject: [PATCH] testing button functionality --- README.md | 2 + random_timer.py | 238 +++++++++++++++--------------------------------- 2 files changed, 73 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index e69de29..2bcc8d5 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,2 @@ +start the virtual env with +source lcd-env/bin/activate \ No newline at end of file diff --git a/random_timer.py b/random_timer.py index 33c9a00..a3c3a63 100755 --- a/random_timer.py +++ b/random_timer.py @@ -1,183 +1,87 @@ #!/usr/bin/env python3 -""" -Catchphrase with LCD Output (Scores & Reset) -""" - -import random import time import threading -import sys +import RPi.GPIO as GPIO from RPLCD.i2c import CharLCD -# ---------- CONFIG ---------- -WORDS_FILE = "words.txt" # file with one word per line -TIMER_SECONDS = 30 # how long the timer runs -I2C_ADDRESS = 0x27 # change if your LCD address is different -I2C_CHIP = 'PCF8574' # common backpack chip +# GPIO pin setup for buttons +BUTTON_START_STOP = 17 +BUTTON_NEXT = 27 +BUTTON_TEAM1 = 22 -# ---------- LCD ---------- -lcd = CharLCD(I2C_CHIP, I2C_ADDRESS) +GPIO.setmode(GPIO.BCM) +GPIO.setup(BUTTON_START_STOP, GPIO.IN, pull_up_down=GPIO.PUD_UP) +GPIO.setup(BUTTON_NEXT, GPIO.IN, pull_up_down=GPIO.PUD_UP) +GPIO.setup(BUTTON_TEAM1, GPIO.IN, pull_up_down=GPIO.PUD_UP) -def lcd_print(text, line=0): - """Print text centered on given LCD line (0 or 1), padded to clear leftovers.""" - lcd.cursor_pos = (line, 0) - lcd.write_string(text.center(16)) +# LCD setup (adjust address and cols/rows if needed) +lcd = CharLCD('PCF8574', 0x27) -def lcd_update_scores(): - """Update the bottom LCD line with team scores (T1 left, T2 right).""" - lcd.cursor_pos = (1, 0) - score_str = f"{score_t1}{' ' * 14}{score_t2}" - lcd.write_string(score_str) +# Game variables +team1_score = 0 +team2_score = 0 +timer_running = False +timer_thread = None +seconds = 0 +winner_displayed = False -# ---------- HELPERS ---------- -def load_words(path=WORDS_FILE): - try: - with open(path, "r", encoding="utf-8") as f: - words = [line.strip() for line in f if line.strip()] - if not words: - raise ValueError("Word file is empty.") - return words - except Exception as e: - print(f"āŒ Error loading words: {e}") - sys.exit(1) +# Timer function +def timer(): + global seconds, timer_running + while timer_running: + seconds += 1 + time.sleep(1) -def pick_random(words): - return random.choice(words) +def update_lcd(): + global winner_displayed + lcd.clear() + if winner_displayed: + if team1_score >= 7: + lcd.write_string("Team 1 Wins!") + elif team2_score >= 7: + lcd.write_string("Team 2 Wins!") + else: + lcd.write_string(f"T1:{team1_score} T2:{team2_score}") + lcd.crlf() + lcd.write_string(f"Time: {seconds}s") -# ---------- TIMER THREAD ---------- -class CountdownTimer(threading.Thread): - def __init__(self, seconds=TIMER_SECONDS, on_finish=None): - super().__init__() - self.seconds = seconds - self.on_finish = on_finish - self._running = threading.Event() - self._running.set() +def start_stop_timer(channel): + global timer_running, timer_thread + if not timer_running: + timer_running = True + threading.Thread(target=timer, daemon=True).start() + else: + timer_running = False - def run(self): - for _ in range(self.seconds): - if not self._running.is_set(): - break - time.sleep(1) - self._running.clear() - if self.on_finish: - self.on_finish() +def next_pressed(channel): + global team1_score, team2_score, winner_displayed + if not winner_displayed: + team2_score += 1 + check_winner() + update_lcd() - def stop(self): - self._running.clear() +def team1_pressed(channel): + global team1_score, winner_displayed + if not winner_displayed: + team1_score += 1 + check_winner() + update_lcd() - @property - def is_running(self): - return self._running.is_set() +def check_winner(): + global winner_displayed, timer_running + if team1_score >= 7 or team2_score >= 7: + winner_displayed = True + timer_running = False -# ---------- SCORE VARIABLES ---------- -score_t1 = 0 -score_t2 = 0 +# Attach button event listeners +GPIO.add_event_detect(BUTTON_START_STOP, GPIO.FALLING, callback=start_stop_timer, bouncetime=300) +GPIO.add_event_detect(BUTTON_NEXT, GPIO.FALLING, callback=next_pressed, bouncetime=300) +GPIO.add_event_detect(BUTTON_TEAM1, GPIO.FALLING, callback=team1_pressed, bouncetime=300) -def add_score(team): - global score_t1, score_t2 - if team == 1: - score_t1 += 1 - if score_t1 >= 7: - print("šŸ† Team 1 wins! Scores reset.") - score_t1 = score_t2 = 0 - elif team == 2: - score_t2 += 1 - if score_t2 >= 7: - print("šŸ† Team 2 wins! Scores reset.") - score_t1 = score_t2 = 0 - lcd_update_scores() - -def reset_scores(): - global score_t1, score_t2 - score_t1 = score_t2 = 0 - lcd_update_scores() - -# ---------- MAIN LOOP ---------- -def main(): - global score_t1, score_t2 - words = load_words() - timer_thread = None - - print("=== Catchphrase, with LCD & Scores ===") - print("Commands:") - print(" start - start 30s timer & show a word") - print(" next - show another word while timer runs") - print(" stop - stop timer early") - print(" t1 - add point to Team 1") - print(" t2 - add point to Team 2") - print(" reset - reset both scores to 0") - print(" exit / quit - leave the program") - - lcd_print("Ready", line=0) - lcd_update_scores() - - def announce_finish(): - print("\nā° Time is up! Returning to menu.") - lcd_print("Time is up!", line=0) - lcd_update_scores() - - while True: - try: - cmd = input("\n> ").strip().lower() - except EOFError: - break - - if cmd in ("exit", "quit"): - if timer_thread and timer_thread.is_running: - timer_thread.stop() - timer_thread.join() - lcd_print("Goodbye!", line=0) - lcd_update_scores() - print("šŸ‘‹ Goodbye!") - break - - elif cmd == "start": - if timer_thread and timer_thread.is_running: - print("[!] Timer is already running.") - else: - timer_thread = CountdownTimer(on_finish=announce_finish) - timer_thread.daemon = True - timer_thread.start() - - word = pick_random(words) - print(word) - lcd_print(word, line=0) - lcd_update_scores() - print(f"[+] 30-second timer started. ({TIMER_SECONDS}s)") - - elif cmd == "next": - if not (timer_thread and timer_thread.is_running): - print("[!] No active timer - use 'start' first.") - else: - word = pick_random(words) - print(word) - lcd_print(word, line=0) - lcd_update_scores() - - elif cmd == "stop": - if timer_thread and timer_thread.is_running: - timer_thread.stop() - timer_thread.join() - lcd_print("Stopped early", line=0) - lcd_update_scores() - print("[+] Timer stopped early.") - else: - print("[!] There is no running timer to stop.") - - elif cmd == "t1": - add_score(1) - print(f"Team 1: {score_t1}, Team 2: {score_t2}") - - elif cmd == "t2": - add_score(2) - print(f"Team 1: {score_t1}, Team 2: {score_t2}") - - elif cmd == "reset": - reset_scores() - print("Scores reset.") - - else: - print(f"[!] Unknown command: {cmd}") - -if __name__ == "__main__": - main() +try: + while True: + update_lcd() + time.sleep(0.5) +except KeyboardInterrupt: + GPIO.cleanup() + lcd.clear()