"""predatorctl – command line interface for Predator Control. Examples: predatorctl status predatorctl profile performance predatorctl fans max | auto | custom 60 70 | curve predatorctl kbd static '#ff0000' --brightness 255 predatorctl kbd off predatorctl lightbar wave --color '#00ffcc' --speed 7 predatorctl battery-limit on predatorctl open rgb (opens the main window on a given page) """ import argparse import json import os import subprocess import sys from .client import Client, DaemonError, read_state def _bool(v): return v.lower() in ("1", "on", "true", "yes") def main(argv=None): p = argparse.ArgumentParser(prog="predatorctl", description="Predator Control CLI") sub = p.add_subparsers(dest="cmd", required=True) sub.add_parser("status", help="show status") sp = sub.add_parser("state", help="raw state as JSON") sp.add_argument("--cached", action="store_true", help="read state.json instead of asking the daemon") sub.add_parser("restore", help="re-apply saved settings") sp = sub.add_parser("profile", help="set power profile") sp.add_argument("profile") sp = sub.add_parser("profile-cycle", help="switch to the next profile") sp = sub.add_parser("fans", help="fan mode") sp.add_argument("mode", choices=["auto", "max", "custom", "curve"]) sp.add_argument("cpu", nargs="?", type=int) sp.add_argument("gpu", nargs="?", type=int) sp = sub.add_parser("kbd", help="keyboard lighting (effect name, 'on' or 'off')") sp.add_argument("effect") sp.add_argument("color", nargs="?") sp.add_argument("--brightness", "-b", type=int) sp = sub.add_parser("kbd-brightness", help="keyboard brightness 0-255 or +/-step") sp.add_argument("value") sp = sub.add_parser("preset", help="load a keyboard preset") sp.add_argument("name") sp = sub.add_parser("lightbar", help="Lightbar") sp.add_argument("mode", nargs="?") sp.add_argument("--color", "-c") sp.add_argument("--brightness", "-b", type=int) sp.add_argument("--speed", "-s", type=int) sp.add_argument("--sync", choices=["on", "off"]) sp = sub.add_parser("battery-limit", help="80 %% charge limit") sp.add_argument("value", choices=["on", "off"]) sp = sub.add_parser("update", help="check for and install updates") sp.add_argument("--check", action="store_true", help="only check, do not install") sp.add_argument("--yes", "-y", action="store_true", help="install without asking") sp = sub.add_parser("open", help="open the main window") sp.add_argument("page", nargs="?", default="home") a = p.parse_args(argv) if a.cmd == "open": subprocess.Popen(["predator-control", "--page", a.page], start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return 0 if a.cmd == "state" and a.cached: print(json.dumps(read_state())) return 0 c = Client() try: if a.cmd == "status": st = c.call("state") s, b = st["sensors"], st["battery"] lbl = st["profile_labels"].get(st["profile"], st["profile"]) print("Profile: %s" % lbl) print("CPU: %s °C %s %% fan %s RPM" % (s["cpu_temp"], st["cpu_load"], s["cpu_fan"])) print("GPU: %s fan %s RPM" % ("%s °C" % s["gpu_temp"] if s["gpu_temp"] else "asleep", s["gpu_fan"])) print("Fan mode: %s" % st["config"]["fans"]["mode"]) line = "Battery: %s %% (%s), AC: %s" % (b.get("capacity"), b.get("status"), "yes" if b["ac_online"] else "no") if b.get("power_w"): line += ", %s %.1f W" % ("charging at" if b.get("charging") else "drawing", b["power_w"]) if b.get("minutes_left") is not None: h, m = divmod(b["minutes_left"], 60) line += ", %d:%02d h %s" % (h, m, "until full" if b.get("charging") else "left") print(line) k = st["config"]["keyboard"] print("Keyboard: %s %s brightness %s" % (k["effect"], k["color"], k["brightness"])) for k, v in st["errors"].items(): print("Error [%s]: %s" % (k, v)) elif a.cmd == "state": print(json.dumps(c.call("state"))) elif a.cmd == "restore": c.call("restore") elif a.cmd == "profile": c.call("set_profile", profile=a.profile) elif a.cmd == "profile-cycle": st = c.call("state") ch = st["profile_choices"] nxt = ch[(ch.index(st["profile"]) + 1) % len(ch)] if st["profile"] in ch else ch[0] c.call("set_profile", profile=nxt) print(st["profile_labels"].get(nxt, nxt)) elif a.cmd == "fans": args = {"mode": a.mode} if a.cpu is not None: args["cpu"] = a.cpu if a.gpu is not None: args["gpu"] = a.gpu c.call("set_fans", **args) elif a.cmd == "kbd": args = {"effect": a.effect} if a.color: args["color"] = a.color if a.color.startswith("#") else "#" + a.color if a.brightness is not None: args["brightness"] = a.brightness c.call("set_keyboard", **args) elif a.cmd == "kbd-brightness": cur = c.call("state")["config"]["keyboard"]["brightness"] v = a.value val = cur + int(v) if v[0] in "+-" else int(v) c.call("set_keyboard", brightness=max(0, min(255, val))) elif a.cmd == "preset": c.call("load_preset", name=a.name) elif a.cmd == "lightbar": args = {"mode": a.mode} if a.mode else {} if a.color: args["color"] = a.color if a.color.startswith("#") else "#" + a.color if a.brightness is not None: args["brightness"] = a.brightness if a.speed is not None: args["speed"] = a.speed if a.sync: args["sync_keyboard"] = a.sync == "on" c.call("set_lightbar", **args) elif a.cmd == "update": u = c.call("check_update") if not u["available"]: print("Predator Control %s is up to date." % u["current"]) return 0 print("Update available: %s -> %s\n%s" % (u["current"], u["latest"], u["url"])) if a.check: return 0 if not u["can_install"]: print("Automatic install needs the pacman package. Update with: git pull && sudo ./install.sh") return 1 if not a.yes and sys.stdin.isatty() and input("Install now? [Y/n] ").strip().lower() not in ("", "y", "yes"): return 0 c.call("install_update") print("Installing %s in the background (journalctl -fu predator-control-update)." % u["asset"]) elif a.cmd == "battery-limit": c.call("set_battery_limit", enabled=_bool(a.value)) except DaemonError as e: print("Error: %s" % e, file=sys.stderr) return 1 return 0 if __name__ == "__main__": sys.exit(main())