#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Touch-aktiviertes Backlight fürs offizielle 7"-RPi-Display (oder andere Touchscreens).
# - Bildschirm bleibt AN, solange Touch-Aktivität kommt.
# - Nach 60 s ohne Touch -> AUS.
# - Bei neuem Touch -> wieder AN.
#
# Abhängigkeit: python3-evdev
# Kompatibel mit alten evdev-Versionen (set_nonblocking / set_blocking Fallback).

IDLE_SECONDS = 60
BACKLIGHT_POWER = "/sys/class/backlight/rpi_backlight/bl_power"  # 0=an, 1=aus

import sys, time, signal, errno, select
from evdev import InputDevice, list_devices, ecodes

running = True

def set_backlight(on):
    val = "0" if on else "1"
    try:
        with open(BACKLIGHT_POWER, "w") as f:
            f.write(val)
    except Exception as e:
        sys.stderr.write("[touch_backlight] Fehler beim Schreiben {0}: {1}\n".format(BACKLIGHT_POWER, e))

def get_backlight_is_on():
    try:
        with open(BACKLIGHT_POWER) as f:
            return f.read().strip() == "0"
    except Exception:
        return True  # konservativ: 'an' annehmen

def find_touch_devices():
    devices = []
    for path in list_devices():
        try:
            dev = InputDevice(path)
        except Exception:
            continue
        name = (dev.name or "").lower()
        caps = dev.capabilities()
        has_abs = False
        try:
            # Alte evdev-Versionen liefern dict; neue liefern dict
            for code in caps.keys():
                if code == ecodes.EV_ABS:
                    has_abs = True
                    break
        except Exception:
            pass

        has_btn_touch = False
        try:
            if ecodes.EV_KEY in caps:
                keys = caps[ecodes.EV_KEY]
                # keys kann Liste von ints oder (code, name)-Tupel sein
                for k in keys:
                    keycode = k if isinstance(k, int) else k[0]
                    if keycode == ecodes.BTN_TOUCH:
                        has_btn_touch = True
                        break
        except Exception:
            pass

        # Bevorzugt typische Touch-Geräte
        if ("ft5406" in name) or ("raspberry" in name) or ("touch" in name):
            devices.append(dev)
        elif has_abs or has_btn_touch:
            devices.append(dev)

    # Eindeutig machen
    uniq = {}
    for d in devices:
        key = getattr(d, 'phys', d.path)
        uniq[key] = d
    return list(uniq.values())

def main():
    global running
    def handle_sigterm(signum, frame):
        global running
        running = False
    signal.signal(signal.SIGTERM, handle_sigterm)
    signal.signal(signal.SIGINT, handle_sigterm)

    touch_devs = find_touch_devices()
    if not touch_devs:
        sys.stderr.write("[touch_backlight] Kein Touch-Input-Gerät gefunden.\n")
        return 1

    # Nonblocking setzen (kompatibel mit alt/neu)
    for d in touch_devs:
        try:
            if hasattr(d, "set_nonblocking"):
                d.set_nonblocking(True)
            else:
                d.set_blocking(False)
        except Exception:
            pass

    poller = select.poll()
    for d in touch_devs:
        try:
            poller.register(d.fileno(), select.POLLIN)
        except Exception:
            pass

    last_touch = time.time()
    set_backlight(True)  # beim Start AN

    while running:
        now = time.time()
        events = []
        try:
            events = poller.poll(500)  # bis zu 500 ms warten
        except Exception:
            pass

        if events:
            for d in touch_devs:
                while True:
                    try:
                        for ev in d.read():
                            # Jede Key- oder ABS-Bewegung als Aktivität werten
                            if ev.type == ecodes.EV_KEY or ev.type == ecodes.EV_ABS:
                                last_touch = now
                                if not get_backlight_is_on():
                                    set_backlight(True)
                    except OSError as e:
                        if e.errno in (errno.EWOULDBLOCK, errno.EAGAIN):
                            break
                        else:
                            # Gerät evtl. weg? Ignorieren und weiter.
                            break
                    except Exception:
                        break

        # Idle → ausschalten
        if (now - last_touch) >= IDLE_SECONDS:
            if get_backlight_is_on():
                set_backlight(False)

        time.sleep(0.1)

    return 0

if __name__ == "__main__":
    sys.exit(main())

