#!/usr/bin/env python3
import os, select, sys, termios, time; args = sys.argv
if len(args) < 4 or args[3] not in {"set", "real", "on", "off"}: raise SystemExit("Use: PORT ADDRESS COMMAND [V]")
port, address, action = args[1], int(args[2]), args[3]
voltage = int(args[4]) if action == "set" and len(args) == 5 else None
if not 0 <= address <= 31 or action == "set" and (voltage is None or not 0 <= voltage <= 250):
    raise SystemExit("Address: 0..31; voltage: 0..250 V.")
commands = {"real": ("NAP", "???"), "on": ("OUT", "1"), "off": ("OUT", "0")}
command, value = ("NAP", f"{voltage:03d}") if action == "set" else commands[action]
payload = f"{address:02X}{command}{value}"; frame = f"@{payload}{sum(payload.encode()) & 255:02X}\r".encode()
fd = os.open(port, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK); cfg = termios.tcgetattr(fd)
cfg[:4] = [0, 0, termios.CS8 | termios.CLOCAL | termios.CREAD, 0]
cfg[4:6] = [termios.B9600, termios.B9600]; cfg[6][termios.VMIN] = cfg[6][termios.VTIME] = 0
termios.tcsetattr(fd, termios.TCSANOW, cfg); termios.tcflush(fd, termios.TCIOFLUSH); os.write(fd, frame)
data, deadline = b"", time.monotonic() + 1.0
while b"\r" not in data and time.monotonic() < deadline:
    if select.select([fd], [], [], 0.1)[0]: data += os.read(fd, 256)
os.close(fd)
if not data: raise SystemExit("No response received.")
text = data.rstrip(b"\r").decode(); print(int(text[-3:]) if action == "real" and text[-3:].isdigit() else text)
