Files
2025-11-15 18:02:39 -05:00

68 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Ultra-responsive fan control every key press is sent instantly.
Uses raw stdin + select() with zero timeout.
"""
import serial
import sys
import select
import termios
import tty
import serial.tools.list_ports
# -------------------------------------------------
# Auto-detect Arduino port
# -------------------------------------------------
def find_arduino():
for p in serial.tools.list_ports.comports():
if 'Arduino' in p.description or 'ACM' in p.device or 'USB' in p.device:
return p.device
return None
PORT = find_arduino() or '/dev/ttyACM0'
BAUD = 115200
# -------------------------------------------------
def raw_stdin():
"""Put stdin into raw mode and return old settings."""
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
tty.setraw(fd)
return old
# -------------------------------------------------
def main():
# --- open serial -------------------------------------------------
try:
ser = serial.Serial(PORT, BAUD, timeout=0) # non-blocking
except Exception as e:
sys.exit(f"Cannot open {PORT}: {e}")
print(f"Connected to {PORT}")
print("Keys: 0-9, f=full, s=stop, q=quit (every press is sent immediately)")
old_term = raw_stdin()
try:
while True:
# ---- non-blocking read from keyboard (0-second timeout) ----
rlist, _, _ = select.select([sys.stdin], [], [], 0)
if rlist:
key = sys.stdin.read(1) # exactly one char
if key.lower() == 'q':
print("\nBye!")
break
ser.write(key.encode()) # send raw byte
print(f"{key}", end='', flush=True)
# ---- echo any reply from Arduino (non-blocking) ----
if ser.in_waiting:
reply = ser.read(ser.in_waiting).decode(errors='ignore')
print(reply, end='', flush=True)
finally:
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_term)
ser.close()
if __name__ == '__main__':
main()