68 lines
2.1 KiB
Python
68 lines
2.1 KiB
Python
#!/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()
|