#!/usr/bin/env python3 # -*- coding: utf-8 -*- from enum import Enum, StrEnum # reads and writes RGB and brightness data for led background color of Clevo NL51 Laptops # ensure to compile drivers before ! read: https://wiki.siningsoft.de/doku.php?id=terra:1500p # Kernelmodul: tuxedo_keyboard # 2026-02-02 - devnull - initial # 2026-02-03 - devnull - added Brightness restore # 2026-02-04 - devnull - JSON statefile # 2026-02-11 - devnull - created class # 2026-02-18 - devnull - added logging # 2026-02-19 - devnull - added commandline arguments for changing # 2026-02-21 - devnull - color and brightness switching on commandline # 2026-02-21 - devnull - enable/disable LED via Commandline ver="1.4" import sys import argparse import json import logging # start with a logger object log = logging.getLogger(__name__) class kbdLED_class(): # 2026-02-11 - devnull - added class definition # 2026-02-19 - devnull - bugfixed write procedure # - added hard coded colors class colors(StrEnum): GREEN = "0 255 0" WHITE = "255 255 255" RED = "255 0 0" BLUE = "0 0 255" YELLOW = "255 255 0" PURPLE = "255 0 255" LIGHTBLUE = "0 0 255" # d_GREEN = {"R":0,"G": 255,"B": 0} # d_WHITE = {"R":255,"G": 255,"B": 255} # d_RED = {"R":255,"G": 0,"B": 0} # d_BLUE = {"R":0,"G": 0,"B": 255} # d_YELLOW = {"R":255,"G": 255,"B": 0} # d_PURPLE = {"R":255,"G": 0,"B": 255} # d_LIGHTBLUE = {"R":0,"G": 255,"B": 255} # diese Versionsnummer wird getrennt vom Programmcode geführt, da es sich getrennt entwickeln wird __version__ = 1.1 config = dict() # Objekt erzeugen def __init__(self, cmd, log, INcolor=colors.WHITE, INbrightness=255, kbd_state_fp='/var/lib/kbdLED.state.json', sysfs_color_fp='/sys/devices/platform/tuxedo_keyboard/leds/rgb:kbd_backlight/multi_intensity', sysfs_bri_fp='/sys/devices/platform/tuxedo_keyboard/leds/rgb:kbd_backlight/brightness'): self.log = log self.config = {"sysfs" : { "color" : sysfs_color_fp , "bri" : sysfs_bri_fp }, "state" : kbd_state_fp} self.log.debug(str(self.config)) # startup and restore states if cmd=="start": self.readStateFile(self.config['state']) self.log.debug(str(self.config)) self.writeColor() self.writeBrightness() # shutdown system and save last states elif cmd=="stop": self.readColor() self.readBrightness() self.writeStateFile(self.config['state']) # set the color from commandline elif cmd=="color": self.log.debug("INcolor=" + str(INcolor)) self.color2dict2config(INcolor) self.log.debug("__init__(cmd=color).config['color']=" + str(self.config['color'])) self.writeColor() # set the brightness from commandline elif cmd=="brightness": self.config['Brightness']= int(INbrightness) self.writeBrightness() def readStateFile(self,kbd_state_fp): config = {"color": {"R": 255, "G": 255, "B": 255}, "Brightness": 255 } try: with open(kbd_state_fp, 'r') as kbd_state_fh: self.config = json.load(kbd_state_fh) except FileNotFoundError: self.log.error("keine Statusdatei gefunden, nutze Standardwerte") except PermissionError: self.log.error("Fehler beim lesen") def writeStateFile(self,kbd_state_fp): try: with open(kbd_state_fp, 'w') as kbd_state_fh: json.dump(self.config,kbd_state_fh) except FileNotFoundError: self.log.error("Verzeichnis oder Datei nicht gefunden") # color String nach Config Dict def color2dict2config(self, color_string): ca=color_string.split(" ") self.log.debug("color_string=" + color_string) self.log.debug("after splitting=" + str(ca)) self.config['color'] = {"R": int(ca[0]), "G": int(ca[1]), "B": int(ca[2])} # color Confi Dict nach String def config2dict2color(self): return str(self.config['color']['R']) + " " + str(self.config['color']['G']) + " " + str(self.config['color']['B']) # reads the color Values from sysfs def readColor(self): try: with open(self.config['sysfs']['color']) as fh: self.color2dict2config(fh.read()) except FileNotFoundError: self.log.error("fehler beim Öffnen der Sysfs Datei " + self.config['sysfs']['color']) sys.exit(1) except PermissionError: self.log.error("keine Rechte die Datei zu lesen " + self.config['sysfs']['color']) sys.exit(1) # writes the color values to sysfs def writeColor(self): try: #with open(self.config['sysfs']['color']) as fh: # fh.write(self.dict2color()) fh = open(self.config['sysfs']['color'], 'w') fh.write(self.config2dict2color()) fh.close() except FileNotFoundError: self.log.error("fehler beim Schreiben der Sysfs Datei " + self.config['sysfs']['color']) sys.exit(1) except PermissionError: self.log.error("keine Rechte die Datei zu schreiben " + self.config['sysfs']['color']) sys.exit(1) # reads Brightness from sysfs def readBrightness(self): try: with open(self.config['sysfs']['bri']) as fh: self.config['Brightness'] = int(fh.read()) except FileNotFoundError: self.log.error("fehler beim Öffnen der Sysfs Datei " + self.config['sysfs']['bri']) sys.exit(1) except PermissionError: self.log.error("keine Rechte die Datei zu lesen " + self.config['sysfs']['bri']) sys.exit(1) # writes Brightness to sysfs def writeBrightness(self): try: #with open(self.config['sysfs']['bri']) as fh: # fh.write(self.config['Brightness']) fh = open(self.config['sysfs']['bri'], 'w') fh.write(str(self.config['Brightness'])) fh.close() except FileNotFoundError: self.log.error("- fehler beim Schreiben der Sysfs Datei " + self.config['sysfs']['bri']) sys.exit(1) except PermissionError: self.log.error("- keine Rechte die Datei zu schreiben " + self.config['sysfs']['bri']) sys.exit(1) # Press the green button in the gutter to run the script. # noinspection aK if __name__ == '__main__': #https: // argparse.readthedocs.io # internal note: um mehrere sich ausschließende Argumente zuzulassen, muss add_mutually_exclusive_groups verwenden parser = argparse.ArgumentParser( prog='T1500_KeyboardLED', description='saves and restore LED Colors', epilog='GPL') group_common = parser.add_argument_group("common") output = group_common.add_mutually_exclusive_group(required=False) output.add_argument('--verbose', action='store_true', help='extended logging', required=False) output.add_argument('--debug', action='store_true', help='debug output', required=False) group_function = parser.add_argument_group("function") startstop = group_function.add_mutually_exclusive_group() startstop.add_argument('--on', action='store_true', help='generally turn LED Backlight on') startstop.add_argument('--off', action='store_true', help='generally turn LED Backlight off') startstop.add_argument('--start', action='store_true', help='will be used for system starts') startstop.add_argument('--stop', action='store_true', help='will be used for system shutdowns') startstop.add_argument('-c', '--color', choices=['white','blue','lightblue','green','red','purple','yellow'], help='keyboard color out of fixed feature set', required=False) startstop.add_argument('-b', '--brightness', type=int, help='keybpoard brightness between 0..255', required=False) startstop.add_argument('--version', action='version', version='%(prog)s ' + ver, default='d') args = parser.parse_args() if args.verbose: log.setLevel(logging.INFO) elif args.debug: log.setLevel(logging.DEBUG) else: log.setLevel(logging.ERROR) logging.basicConfig(format='%(asctime)s %(message)s') if args.start: print("Keyboard: read and set Color and Brightness") log.debug("System start") kL = kbdLED_class("start", log) elif args.stop: print("Keyboard: read and save Color and Brightness") log.debug("System stop") kL = kbdLED_class("stop", log) elif args.color: print("Keyboard: set color " + args.color) log.debug("resolveed Color=" + getattr(kbdLED_class.colors,args.color.upper())) try: log.debug("setup keyboard color " + args.color) kL = kbdLED_class("color", log, INcolor=getattr(kbdLED_class.colors, args.color.upper())) except AttributeError: log.error("color does not exists " + args.color) parser.print_help() sys.exit((1)) elif args.brightness: print("Keyboard: set brightness " + str(args.brightness)) log.debug("setup keyboard brightness " + str(args.brightness)) kL = kbdLED_class("brightness",log, INbrightness=args.brightness) elif args.on: print("Keyboard: enable Backlight LED") kL = kbdLED_class("brightness",log, INbrightness=255) elif args.off: print("Keyboard: disable Backlight LED") kL = kbdLED_class("brightness", log, INbrightness=0) else: parser.print_help() sys.exit((10)) sys.exit(0)