"""Build control payloads without exposing packet layout to the GUI. Framing and sequence numbers belong to Session. These helpers describe user actions and return payloads only; they do not connect or send anything. """ from controller.protocol import EQ, LIGHTS SOURCES = {"Bluetooth": 1, "USB 1": 2, "USB 2": 3, "AUX 1": 4, "AUX 2": 5} KEYS = {"volume_up": 15, "volume_down": 16, "play_pause": 17, "mute": 20} def set_eq(preset): if preset not in EQ.values(): raise ValueError("Unknown EQ preset") return bytes((0x40, 3, 0, preset, 0)) def set_bass(enabled): # Samsung's bass flag is inverted: 0 means on, 1 means off. return bytes((0x40, 4, 0, 0 if enabled else 1, 0)) def set_lighting(mode): if mode not in LIGHTS.values(): raise ValueError("Unknown lighting mode") return bytes((0x50, 3, mode)) def set_source(source): if source not in SOURCES.values(): raise ValueError("Unknown source") return bytes((0x30, source)) def set_rgb(red, green, blue): if any(type(value) is not int or not 0 <= value <= 255 for value in (red, green, blue)): raise ValueError("RGB values must be integers between 0 and 255") return bytes((0x60, 2, red, green, blue)) def remote_key(action): try: return bytes((0x70, KEYS[action])) except KeyError as exc: raise ValueError("Unknown remote action") from exc def lighting_status(): return b"\x52\x03" def status_queries(): return b"\x42\x03", lighting_status() def initial_queries(): return b"\x32", b"\x42\x03"