From 6efdd836a689bc5749de9ab0ed1361d11be0c0f6 Mon Sep 17 00:00:00 2001 From: Till Immer Date: Sun, 23 Aug 2026 18:01:39 +0000 Subject: [PATCH] =?UTF-8?q?capture=5Fir.py=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- capture_ir.py | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 capture_ir.py diff --git a/capture_ir.py b/capture_ir.py new file mode 100644 index 0000000..4164696 --- /dev/null +++ b/capture_ir.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +""" +IR Capture Script +- Führt mode2 --device /dev/lirc1 aus +- Wandelt pulse/space/timeout in mark/space JSON um +- Speichert die JSON-Datei +- Fügt optional einen neuen Command in die Config ein +""" + +import subprocess +import json +import os +import sys +import re +from pathlib import Path + +# === Anpassbare Pfade === +DEVICE = "/dev/lirc1" +IR_SENDER_DIR = Path("/home/till/IrSender2") +CONFIG_FILE = IR_SENDER_DIR / "config.json" # ggf. anpassen +IR_SEND_SCRIPT = IR_SENDER_DIR / "ir_send.py" +CARRIER = 38000 +REPEAT = 1 + +def capture_mode2(): + """Startet mode2 und liest pulse/space/timeout-Daten.""" + print(f"Starte mode2 auf {DEVICE} ...") + print("Drücke jetzt die Taste auf der Fernbedienung.") + print("Warte auf Signal (timeout = Ende). Mit Ctrl+C abbrechen.\n") + + try: + proc = subprocess.Popen( + ["mode2", "--device", DEVICE], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1 + ) + except FileNotFoundError: + print("Fehler: 'mode2' nicht gefunden. Ist LIRC installiert?") + sys.exit(1) + except PermissionError: + print(f"Fehler: Keine Berechtigung für {DEVICE}. Mit sudo ausführen?") + sys.exit(1) + + signals = [] + + try: + for line in proc.stdout: + line = line.strip() + if not line: + continue + + # mode2 Ausgabe: "pulse 1234", "space 5678" oder "timeout 21585" + m = re.match(r"^(pulse|space|timeout)\s+(\d+)$", line, re.IGNORECASE) + if not m: + # z.B. "Using device: ..." ignorieren + continue + + kind, duration = m.group(1).lower(), int(m.group(2)) + + if kind == "timeout": + # timeout → abschließender space (wie in deinem Original-Beispiel) + signals.append({"type": "space", "duration": duration}) + print(f" space {duration} (timeout → Signalende)") + print("\nTimeout erkannt – Signal aufgenommen.") + break + + # pulse → mark, space → space + typ = "mark" if kind == "pulse" else "space" + signals.append({"type": typ, "duration": duration}) + print(f" {typ:5} {duration}") + + except KeyboardInterrupt: + print("\nAbbruch durch Benutzer – vorhandene Daten werden verwendet.") + finally: + proc.terminate() + try: + proc.wait(timeout=1) + except subprocess.TimeoutExpired: + proc.kill() + + return signals + +def save_json(signals, filename: Path): + """Speichert das Signal im gewünschten Format.""" + data = { + "carrier": CARRIER, + "repeat": REPEAT, + "signal": signals + } + with open(filename, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2) + print(f"\nJSON gespeichert: {filename}") + +def add_command_to_config(command_name: str, json_filename: str, web_title: str): + """Fügt einen neuen Command in die Config-Datei ein.""" + if not CONFIG_FILE.exists(): + print(f"Warnung: Config-Datei {CONFIG_FILE} nicht gefunden – Command wird nicht hinzugefügt.") + return + + with open(CONFIG_FILE, "r", encoding="utf-8") as f: + config = json.load(f) + + if "commands" not in config: + config["commands"] = {} + + if command_name in config["commands"]: + print(f"Warnung: Command '{command_name}' existiert bereits – wird überschrieben.") + + config["commands"][command_name] = { + "description": f"Send IR command {json_filename}", + "web_title": web_title, + "web_enabled": True, + "timeout_seconds": 10, + "command": [ + "python3", + str(IR_SEND_SCRIPT), + str(IR_SENDER_DIR / json_filename) + ] + } + + # Backup anlegen + backup = CONFIG_FILE.with_suffix(".json.bak") + CONFIG_FILE.rename(backup) + print(f"Backup der Config erstellt: {backup}") + + with open(CONFIG_FILE, "w", encoding="utf-8") as f: + json.dump(config, f, indent=2, ensure_ascii=False) + + print(f"Command '{command_name}' zur Config hinzugefügt.") + +def main(): + print("=== IR Capture → JSON + Config ===\n") + + # 1. Signal aufnehmen + signals = capture_mode2() + + if not signals: + print("Keine Daten empfangen. Abbruch.") + sys.exit(1) + + print(f"\n{len(signals)} Einträge aufgenommen.") + + # 2. Dateiname vom Benutzer erfragen + while True: + name = input("Dateiname (ohne .json, z.B. hektagonYellow): ").strip() + if name and re.match(r"^[a-zA-Z0-9_\-]+$", name): + break + print("Nur Buchstaben, Zahlen, _ und - erlaubt.") + + json_path = IR_SENDER_DIR / f"{name}.json" + save_json(signals, json_path) + + # 3. Optional Command in Config eintragen + add = input("\nSoll ein neuer Command in die Config eingetragen werden? [j/N]: ").strip().lower() + if add in ("j", "y", "ja", "yes"): + cmd_name = input(f"Command-Name (Standard: {name}): ").strip() or name + web_title = input(f"Web-Titel (Standard: {name}): ").strip() or name + add_command_to_config(cmd_name, f"{name}.json", web_title) + + print("\nFertig!") + +if __name__ == "__main__": + main() \ No newline at end of file