testing button functionality
This commit is contained in:
238
random_timer.py
238
random_timer.py
@@ -1,183 +1,87 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
|
||||||
Catchphrase with LCD Output (Scores & Reset)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import random
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import sys
|
import RPi.GPIO as GPIO
|
||||||
from RPLCD.i2c import CharLCD
|
from RPLCD.i2c import CharLCD
|
||||||
|
|
||||||
# ---------- CONFIG ----------
|
# GPIO pin setup for buttons
|
||||||
WORDS_FILE = "words.txt" # file with one word per line
|
BUTTON_START_STOP = 17
|
||||||
TIMER_SECONDS = 30 # how long the timer runs
|
BUTTON_NEXT = 27
|
||||||
I2C_ADDRESS = 0x27 # change if your LCD address is different
|
BUTTON_TEAM1 = 22
|
||||||
I2C_CHIP = 'PCF8574' # common backpack chip
|
|
||||||
|
|
||||||
# ---------- LCD ----------
|
GPIO.setmode(GPIO.BCM)
|
||||||
lcd = CharLCD(I2C_CHIP, I2C_ADDRESS)
|
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):
|
# LCD setup (adjust address and cols/rows if needed)
|
||||||
"""Print text centered on given LCD line (0 or 1), padded to clear leftovers."""
|
lcd = CharLCD('PCF8574', 0x27)
|
||||||
lcd.cursor_pos = (line, 0)
|
|
||||||
lcd.write_string(text.center(16))
|
|
||||||
|
|
||||||
def lcd_update_scores():
|
# Game variables
|
||||||
"""Update the bottom LCD line with team scores (T1 left, T2 right)."""
|
team1_score = 0
|
||||||
lcd.cursor_pos = (1, 0)
|
team2_score = 0
|
||||||
score_str = f"{score_t1}{' ' * 14}{score_t2}"
|
timer_running = False
|
||||||
lcd.write_string(score_str)
|
timer_thread = None
|
||||||
|
seconds = 0
|
||||||
|
winner_displayed = False
|
||||||
|
|
||||||
# ---------- HELPERS ----------
|
# Timer function
|
||||||
def load_words(path=WORDS_FILE):
|
def timer():
|
||||||
try:
|
global seconds, timer_running
|
||||||
with open(path, "r", encoding="utf-8") as f:
|
while timer_running:
|
||||||
words = [line.strip() for line in f if line.strip()]
|
seconds += 1
|
||||||
if not words:
|
time.sleep(1)
|
||||||
raise ValueError("Word file is empty.")
|
|
||||||
return words
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error loading words: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def pick_random(words):
|
def update_lcd():
|
||||||
return random.choice(words)
|
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 ----------
|
def start_stop_timer(channel):
|
||||||
class CountdownTimer(threading.Thread):
|
global timer_running, timer_thread
|
||||||
def __init__(self, seconds=TIMER_SECONDS, on_finish=None):
|
if not timer_running:
|
||||||
super().__init__()
|
timer_running = True
|
||||||
self.seconds = seconds
|
threading.Thread(target=timer, daemon=True).start()
|
||||||
self.on_finish = on_finish
|
else:
|
||||||
self._running = threading.Event()
|
timer_running = False
|
||||||
self._running.set()
|
|
||||||
|
|
||||||
def run(self):
|
def next_pressed(channel):
|
||||||
for _ in range(self.seconds):
|
global team1_score, team2_score, winner_displayed
|
||||||
if not self._running.is_set():
|
if not winner_displayed:
|
||||||
break
|
team2_score += 1
|
||||||
time.sleep(1)
|
check_winner()
|
||||||
self._running.clear()
|
update_lcd()
|
||||||
if self.on_finish:
|
|
||||||
self.on_finish()
|
|
||||||
|
|
||||||
def stop(self):
|
def team1_pressed(channel):
|
||||||
self._running.clear()
|
global team1_score, winner_displayed
|
||||||
|
if not winner_displayed:
|
||||||
|
team1_score += 1
|
||||||
|
check_winner()
|
||||||
|
update_lcd()
|
||||||
|
|
||||||
@property
|
def check_winner():
|
||||||
def is_running(self):
|
global winner_displayed, timer_running
|
||||||
return self._running.is_set()
|
if team1_score >= 7 or team2_score >= 7:
|
||||||
|
winner_displayed = True
|
||||||
|
timer_running = False
|
||||||
|
|
||||||
# ---------- SCORE VARIABLES ----------
|
# Attach button event listeners
|
||||||
score_t1 = 0
|
GPIO.add_event_detect(BUTTON_START_STOP, GPIO.FALLING, callback=start_stop_timer, bouncetime=300)
|
||||||
score_t2 = 0
|
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):
|
try:
|
||||||
global score_t1, score_t2
|
while True:
|
||||||
if team == 1:
|
update_lcd()
|
||||||
score_t1 += 1
|
time.sleep(0.5)
|
||||||
if score_t1 >= 7:
|
except KeyboardInterrupt:
|
||||||
print("🏆 Team 1 wins! Scores reset.")
|
GPIO.cleanup()
|
||||||
score_t1 = score_t2 = 0
|
lcd.clear()
|
||||||
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()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user