|
@@ -0,0 +1,278 @@
|
|
|
|
|
+#!/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)
|