import argparse import getpass import json import sys def main(): parser = argparse.ArgumentParser(description='Native Linux-Steuerung für den BTD 700; ohne Firmware-Updates.') parser.add_argument('--device', help='Steuergerät aus dem Befehl devices, z. B. /dev/hidraw6') parser.add_argument('--background', action='store_true', help='Nur im Infobereich starten') parser.add_argument('--demo', action='store_true', help='Vorführmodus ohne USB-Zugriff') parser.add_argument('--smoke-seconds', type=int, default=0, help=argparse.SUPPRESS) subs = parser.add_subparsers(dest='command') subs.add_parser('devices', help='BTD-700-Steuerschnittstellen auflisten') subs.add_parser('status', help='Aktuellen Status als JSON ausgeben (ohne Passwort)') mode = subs.add_parser('mode', help='Audiomodus wählen') mode.add_argument('value', choices=['standard', 'gaming', 'auracast']) mode.add_argument('--transport', choices=['auto', 'classic', 'le']) codec = subs.add_parser('codec', help='Codec im Standard-Modus wählen') codec.add_argument('value', choices=['sbc', 'aptx', 'adaptive', 'lossless', 'qmap', 'lc3']) subs.add_parser('connect', help='Gekoppelte Kopfhörer verbinden') subs.add_parser('disconnect', help='Kopfhörer trennen') broadcast = subs.add_parser('auracast', help='Auracast-Einstellungen speichern') broadcast.add_argument('--name') broadcast.add_argument('--password', action='store_true', help='Neues Passwort verdeckt abfragen') broadcast.add_argument('--public', choices=['on', 'off']) broadcast.add_argument('--encryption', choices=['on', 'off']) broadcast.add_argument('--quality', choices=['16k', '24k', 'high']) reset = subs.add_parser('reset', help='Alle Kopplungen und Einstellungen löschen') reset.add_argument('--confirm', action='store_true') args = parser.parse_args() if not args.command: try: from .app import run return run(background=args.background, demo=args.demo, device=args.device, smoke_seconds=args.smoke_seconds) except (ImportError, ValueError) as exc: print(f'GTK-Oberfläche nicht verfügbar: {exc}\nAbhängigkeiten: siehe README.md. CLI: ./run.sh status', file=sys.stderr) return 1 from .transport import DeviceError, Hidraw, discover from .controller import Controller from .protocol import ProtocolError if args.command == 'devices': from dataclasses import asdict print(json.dumps([asdict(d) for d in discover()], indent=2)) return 0 transport = None try: if args.demo: from .demo import DemoTransport transport = DemoTransport() else: devices = [d for d in discover() if not args.device or d.path == args.device] if len(devices) != 1: raise DeviceError('Kein eindeutiger BTD 700 gefunden. devices ausführen; bei mehreren Dongles --device angeben.') transport = Hidraw(devices[0]) controller = Controller(transport) if args.command == 'mode': controller.set_mode(['standard', 'gaming', 'auracast'].index(args.value), {'auto': 3, 'classic': 1, 'le': 2}.get(args.transport)) elif args.command == 'codec': controller.set_codec(1 << ['sbc', 'aptx', 'adaptive', 'lossless', 'qmap', 'lc3'].index(args.value)) elif args.command in ('connect', 'disconnect'): controller.set_connection(args.command == 'connect') elif args.command == 'auracast': controller.set_broadcast(name=args.name, password=getpass.getpass('Neues Auracast-Passwort: ') if args.password else None, public=None if args.public is None else args.public == 'on', encrypted=None if args.encryption is None else args.encryption == 'on', quality={'16k': 0, '24k': 1, 'high': 2}.get(args.quality)) elif args.command == 'reset': controller.factory_reset(confirmed=args.confirm) print('Zurücksetzen angefordert. Kopfhörer danach neu koppeln.') return 0 print(json.dumps(controller.snapshot().public_dict(), indent=2, ensure_ascii=False)) return 0 except (OSError, DeviceError, ProtocolError, ValueError) as exc: print(f'Fehler: {exc}', file=sys.stderr) return 1 finally: if transport: transport.close() if __name__ == '__main__': raise SystemExit(main())