from machine import Pin import wifi_client import time # State Constants STATE_USER_ID = 0 STATE_RATING = 1 # Global variables CURRENT_STATE = STATE_USER_ID USER_ID = 0 RATING = 0 BUTTON_SEND = None RATE_BUTTONS = [] DISPLAY = None # Variables for Interrupt (ISR) handling and Debouncing pending_rate_button = -1 pending_send_button = False last_interrupt_time = 0 DEBOUNCE_MS = 250 # Ignore button presses within 250ms of each other # Helper to update display based on state def refresh_display(message=None): if not DISPLAY: return DISPLAY.fill(0) if message: # Show temporary message (Success, Error, Confirmed) DISPLAY.text(message, 10, 30) elif CURRENT_STATE == STATE_USER_ID: # 1. User ID Mode DISPLAY.text("User ID Mode", 15, 0) # Display binary representation: _ _ _ _ _ binary_str = "" for i in range(5): bit_pos = 4 - i if USER_ID & (1 << bit_pos): binary_str += "X " else: binary_str += "_ " DISPLAY.text(binary_str.strip(), 30, 30) elif CURRENT_STATE == STATE_RATING: # 3. Rating Mode DISPLAY.text("Select Rating", 10, 0) if RATING == 0: rating_text = "_" else: rating_text = str(RATING) DISPLAY.text(rating_text, 60, 30) DISPLAY.show() # initialize a specific Pin as Input with a pull-down resistor def initialize_pin(pin_number:int): button = Pin(pin_number, Pin.IN, Pin.PULL_DOWN) return button # Hardware Interrupt: rate button is pressed def rate_button_pressed(pin:Pin) -> None: global pending_rate_button, last_interrupt_time current_time = time.ticks_ms() # Simple software debounce if time.ticks_diff(current_time, last_interrupt_time) > DEBOUNCE_MS: # Find which button index was pressed for i, button in enumerate(RATE_BUTTONS): if button == pin: pending_rate_button = i break last_interrupt_time = current_time # Hardware Interrupt: Send/Confirm button is pressed def sendButton_pressed(pin:Pin) -> None: global pending_send_button, last_interrupt_time current_time = time.ticks_ms() if time.ticks_diff(current_time, last_interrupt_time) > DEBOUNCE_MS: pending_send_button = True last_interrupt_time = current_time # Process the rate button press (Called from the main loop) def process_rate_button(button_index: int): global USER_ID, RATING, CURRENT_STATE if CURRENT_STATE == STATE_USER_ID: bit_pos = 4 - button_index USER_ID ^= (1 << bit_pos) print(f"Current User ID: {USER_ID}") elif CURRENT_STATE == STATE_RATING: RATING = button_index + 1 print(f"Current Rating selected: {RATING}") refresh_display() # Process the send button press (Called from the main loop) def process_send_button(): global CURRENT_STATE, USER_ID, RATING if CURRENT_STATE == STATE_USER_ID: # 2. Confirmed ID display refresh_display(f"Confirmed: {USER_ID}") time.sleep(1) CURRENT_STATE = STATE_RATING refresh_display() elif CURRENT_STATE == STATE_RATING: if RATING == 0: return # Don't send if no rating is selected yet # 4. Sending / Success / Error refresh_display("Sending...") success = wifi_client.send_request(USER_ID, RATING) if success: refresh_display("Success") else: refresh_display("Error") time.sleep(3) # Display status for 3 seconds # Reset for next rating USER_ID = 0 RATING = 0 CURRENT_STATE = STATE_USER_ID refresh_display() # start the rating program def start_rating(rate_button_pins:list, button_send_pin:int, oled_display=None) -> None: global RATE_BUTTONS, BUTTON_SEND, DISPLAY global pending_rate_button, pending_send_button DISPLAY = oled_display # initialize all pins as buttons and attach interrupts RATE_BUTTONS = [] for pin_num in rate_button_pins: button = initialize_pin(pin_num) button.irq(trigger=Pin.IRQ_RISING, handler=rate_button_pressed) RATE_BUTTONS.append(button) # initialize send button and attach interrupt BUTTON_SEND = initialize_pin(button_send_pin) BUTTON_SEND.irq(trigger=Pin.IRQ_RISING, handler=sendButton_pressed) print("System started.") refresh_display() # The Main Event Loop - This safely handles the screen updates while True: if pending_rate_button != -1: process_rate_button(pending_rate_button) pending_rate_button = -1 # Reset the flag if pending_send_button: process_send_button() pending_send_button = False # Reset the flag time.sleep_ms(50) # Short delay to save power and avoid choking the CPU