Implement snapshot capability
Rename plugin funcs to make implemenation more intuitive Add ID for snap. Remove redundant left/right id func. Show err if snap file not found Track per-file snapshot error
This commit is contained in:
parent
9f71853179
commit
68989ed8e4
8 changed files with 128 additions and 30 deletions
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
|
@ -6,11 +6,12 @@
|
|||
"configurations": [
|
||||
{
|
||||
"name": "Python: Current File",
|
||||
"type": "python",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
"justMyCode": true,
|
||||
"args": ["-ls", "left-snap.json", "-rs", "right-snap.json"]
|
||||
}
|
||||
]
|
||||
}
|
45
drawing.py
45
drawing.py
|
@ -6,6 +6,8 @@ import importlib.util
|
|||
import sys
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Internal Dependencies
|
||||
from commands import Commands, send_command
|
||||
|
@ -89,6 +91,21 @@ def draw_bar(grid, bar_ratio, bar_value, bar_x_offset = 1, y=0):
|
|||
grid[bar_x_offset+i,33-pixels_col:33] = bar_value
|
||||
else:
|
||||
grid[bar_x_offset+i,1:1+pixels_col] = bar_value
|
||||
|
||||
warned = set()
|
||||
def draw_snapshot(grid, fill_value, file, path, panel):
|
||||
global warned
|
||||
subdirs = [ f.name for f in os.scandir(path) if f.is_dir() and f.name in ['left', 'right']]
|
||||
subdir = panel if panel in subdirs else ''
|
||||
try:
|
||||
with open(os.path.join(path, subdir, file)) as f:
|
||||
snap = json.load(f)
|
||||
grid[:,:] = np.array(snap).T * fill_value
|
||||
except FileNotFoundError as e:
|
||||
if not file in warned:
|
||||
print(f"File {file} not found")
|
||||
warned.add(file)
|
||||
|
||||
|
||||
## Border Draw Functions ##
|
||||
|
||||
|
@ -141,7 +158,7 @@ def draw_outline_border(grid, border_value):
|
|||
grid[8, :] = border_value # Right
|
||||
|
||||
# Maps an app arg value to abstract app and border draw functions
|
||||
metrics_funcs = {
|
||||
direct_draw_funcs = {
|
||||
"cpu": {
|
||||
"fn": draw_spiral_vals,
|
||||
"border": draw_8_x_8_grid
|
||||
|
@ -162,6 +179,10 @@ metrics_funcs = {
|
|||
"fn": draw_battery,
|
||||
"border": draw_1_x_2_vert_grid
|
||||
},
|
||||
"snap": {
|
||||
"fn": draw_snapshot,
|
||||
"border": lambda *x: None # No border
|
||||
},
|
||||
#noop
|
||||
"none": {
|
||||
"fn": lambda *x: x,
|
||||
|
@ -171,25 +192,23 @@ metrics_funcs = {
|
|||
|
||||
# Draws the app for the specified arg value
|
||||
def draw_app(app, *arguments, **kwargs):
|
||||
metrics_funcs[app].get('fn')(*arguments, **kwargs)
|
||||
direct_draw_funcs[app].get('fn')(*arguments, **kwargs)
|
||||
|
||||
# Draws the border for the specified arg value
|
||||
def draw_app_border(app, *arguments):
|
||||
metrics_funcs[app].get('border')(*arguments)
|
||||
direct_draw_funcs[app].get('border')(*arguments)
|
||||
|
||||
# Draw the IDs of apps currently assigned to the top and bottom of the left panel
|
||||
def draw_ids_left(grid, top_left, bot_left, fill_value):
|
||||
# Draw the IDs of apps currently assigned to the top and bottom of a panel
|
||||
def draw_ids(grid, top_left, bot_left, fill_value):
|
||||
fill_grid_top = id_patterns[top_left]
|
||||
fill_grid_bot = id_patterns[bot_left]
|
||||
grid[1:8, 1:16] = fill_grid_top * fill_value
|
||||
grid[1:8, 18:-1] = fill_grid_bot * fill_value
|
||||
|
||||
# Draw the IDs of apps currently assigned to the top and bottom of the right panel
|
||||
def draw_ids_right(grid, top_right, bot_right, fill_value):
|
||||
fill_grid_top = id_patterns[top_right]
|
||||
fill_grid_bot = id_patterns[bot_right]
|
||||
grid[1:8, 1:16] = fill_grid_top * fill_value
|
||||
grid[1:8, 18:-1] = fill_grid_bot * fill_value
|
||||
# Draw the ID of the app currently assigned to the full panel
|
||||
def draw_id(grid, id, fill_value):
|
||||
fill_grid = id_patterns[id]
|
||||
grid[:,:] = fill_grid * fill_value
|
||||
|
||||
def draw_to_LEDs(s, grid):
|
||||
for i in range(grid.shape[0]):
|
||||
|
@ -245,8 +264,8 @@ if not re.search(r"--disable-plugins|-dp", str(sys.argv)):
|
|||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
for k,v in module.metrics_funcs.items():
|
||||
metrics_funcs[k] = v
|
||||
for k,v in module.direct_draw_funcs.items():
|
||||
direct_draw_funcs[k] = v
|
||||
|
||||
from drawing import id_patterns
|
||||
for k,v in module.id_patterns.items():
|
||||
|
|
0
install_as_service.sh
Normal file → Executable file
0
install_as_service.sh
Normal file → Executable file
|
@ -10,7 +10,7 @@ import os
|
|||
|
||||
|
||||
# Internal Dependencies
|
||||
from drawing import draw_outline_border, draw_ids_left, draw_ids_right, draw_app, draw_app_border, DrawingThread
|
||||
from drawing import draw_outline_border, draw_ids, draw_id, draw_app, draw_app_border, DrawingThread
|
||||
from monitors import CPUMonitor, MemoryMonitor, BatteryMonitor, DiskMonitor, NetworkMonitor, get_monitor_brightness
|
||||
|
||||
# External Dependencies
|
||||
|
@ -101,11 +101,15 @@ def main(args):
|
|||
draw_app(arg, grid, last_network_upload, foreground_value, bar_x_offset=1, y=idx)
|
||||
draw_app(arg, grid, last_network_download, foreground_value, bar_x_offset=5, y=idx)
|
||||
|
||||
def draw_snap(grid, foreground_value, file, snap_path, panel):
|
||||
draw_app("snap", grid, foreground_value, file, snap_path, panel)
|
||||
|
||||
app_functions = {
|
||||
"cpu": draw_cpu,
|
||||
"mem-bat": draw_mem_bat,
|
||||
"disk": draw_disk,
|
||||
"net": draw_net,
|
||||
"snap": draw_snap,
|
||||
"none": lambda *x: x # noop
|
||||
}
|
||||
|
||||
|
@ -126,7 +130,13 @@ def main(args):
|
|||
app_functions[obj["name"]] = obj["fn"]
|
||||
#################################################
|
||||
|
||||
if args.snapshot_duration > args.snapshot_interval:
|
||||
print("Snapshot duration must be less than snapshot interval. Exiting...")
|
||||
sys.exit(0)
|
||||
start_time = time.time()
|
||||
while True:
|
||||
elapsed_time = time.time()
|
||||
show_snapshot = True if args.snapshot_interval == 0 or elapsed_time % args.snapshot_interval <= args.snapshot_duration else False
|
||||
try:
|
||||
screen_brightness = get_monitor_brightness()
|
||||
background_value = int(screen_brightness * (max_background_brightness - min_background_brightness) + min_background_brightness)
|
||||
|
@ -134,26 +144,41 @@ def main(args):
|
|||
grid = np.zeros((9,34), dtype = int)
|
||||
active_keys = device.active_keys(verbose=True)
|
||||
if (MODIFIER_KEYS[0] in active_keys or MODIFIER_KEYS[1] in active_keys) and KEY_I in active_keys and not args.no_key_listener:
|
||||
draw_outline_border(grid, background_value)
|
||||
draw_ids_left(grid, args.top_left, args.bottom_left, foreground_value)
|
||||
if args.left_snap and show_snapshot:
|
||||
draw_id(grid, "snap", foreground_value)
|
||||
else:
|
||||
draw_outline_border(grid, background_value)
|
||||
draw_ids(grid, args.top_left, args.bottom_left, foreground_value)
|
||||
left_drawing_queue.put(grid)
|
||||
grid = np.zeros((9,34), dtype = int)
|
||||
draw_outline_border(grid, background_value)
|
||||
draw_ids_right(grid, args.top_right, args.bottom_right, foreground_value)
|
||||
if args.right_snap and show_snapshot:
|
||||
draw_id(grid, "snap", foreground_value)
|
||||
else:
|
||||
draw_outline_border(grid, background_value)
|
||||
draw_ids(grid, args.top_right, args.bottom_right, foreground_value)
|
||||
right_drawing_queue.put(grid)
|
||||
grid = np.zeros((9,34), dtype = int)
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
# Draw by quadrants (i.e. to top and bottom of left and right panels)
|
||||
# Draw by half or whole panel, depending on program args
|
||||
for i, draw_queue in enumerate(drawing_queues):
|
||||
grid = np.zeros((9,34), dtype = int)
|
||||
if i == 0:
|
||||
panel = 'left'
|
||||
_args = [args.top_left, args.bottom_left]
|
||||
if args.left_snap is not None and show_snapshot:
|
||||
app_functions["snap"](grid, foreground_value, args.left_snap, args.snapshot_path, 'left')
|
||||
draw_queue.put(grid)
|
||||
continue
|
||||
else:
|
||||
_args = [args.top_left, args.bottom_left]
|
||||
else:
|
||||
panel = 'right'
|
||||
if args.right_snap is not None and show_snapshot:
|
||||
app_functions["snap"](grid, foreground_value, args.right_snap, args.snapshot_path, 'right')
|
||||
draw_queue.put(grid)
|
||||
continue
|
||||
_args = [args.top_right, args.bottom_right]
|
||||
grid = np.zeros((9,34), dtype = int)
|
||||
for j, arg in enumerate(_args):
|
||||
if j == 0:
|
||||
idx = 0
|
||||
|
@ -165,7 +190,6 @@ def main(args):
|
|||
func = app_functions[arg]
|
||||
func(arg, grid, foreground_value, idx)
|
||||
except KeyError:
|
||||
print(app_functions.keys())
|
||||
print(f"Unrecognized display option {arg} for {loc} {panel}")
|
||||
if arg == 'mem-bat': arg = 'mem' # Single border draw for mem and bat together
|
||||
draw_app_border(arg, grid, background_value, idx)
|
||||
|
@ -197,12 +221,12 @@ if __name__ == "__main__":
|
|||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
app_names += module.metrics_funcs.keys()
|
||||
app_names += map(lambda o: o["name"], module.app_funcs)
|
||||
#################################################################
|
||||
parser = ArgumentParser(prog="FW LED System Monitor", add_help=False,
|
||||
description="Displays system performance metrics in the Framework 16 LED Matrix input module",
|
||||
formatter_class=ArgumentDefaultsHelpFormatter)
|
||||
mode_group = parser.add_mutually_exclusive_group()
|
||||
mode_group = parser.add_argument_group()
|
||||
mode_group.add_argument("--help", "-h", action="help",
|
||||
help="Show this help message and exit")
|
||||
|
||||
|
@ -215,6 +239,19 @@ if __name__ == "__main__":
|
|||
help="Metrics to display in the top section of the right matrix panel")
|
||||
addGroup.add_argument("--bottom-right", "-br", type=str, default="disk", choices=app_names,
|
||||
help="Metrics to display in the top section of the right matrix panel")
|
||||
addGroup.add_argument("--left-snap", "-ls", type=str, default=None,
|
||||
help="Snapshot file to display on the left panel. Specify * to cycle through all files in the snapshot dir")
|
||||
addGroup.add_argument("--right-snap", "-rs", type=str, default=None,
|
||||
help="Snapshot file to display on the right panel. Specify * to cycle through all files in the snapshot dir")
|
||||
addGroup.add_argument("--snapshot-path", "-sp", type=str, default="snapshot_files",
|
||||
help="The file path that contains either the snapshot files that may be displayed on either panel or " +
|
||||
"'left' and 'right' directories that contain files that may be displayed on the respective panel")
|
||||
addGroup.add_argument("--snapshot-interval", "-si", type=int, default=0,
|
||||
help="The interval (in seconds) at which the selected snapshot files will be rendered. A value " +
|
||||
"of zero means the snapshots should be rendered continuously")
|
||||
addGroup.add_argument("--snapshot-duration", "-sd", type=int, default=0,
|
||||
help="The number of seconds that the snapshot file will be rendered at the specified interval. Must be " +
|
||||
"less than the value of --snapshot-interval")
|
||||
|
||||
addGroup.add_argument("--no-key-listener", "-nkl", action="store_true", help="Do not listen for key presses")
|
||||
addGroup.add_argument("--disable-plugins", "-dp", action="store_true", help="Do not load any plugin code")
|
||||
|
@ -224,6 +261,8 @@ if __name__ == "__main__":
|
|||
print(f"bottom left {args.bottom_left}")
|
||||
print(f"top right {args.top_right}")
|
||||
print(f"bottom right {args.bottom_right}")
|
||||
print(f"left snap {args.left_snap}")
|
||||
print(f"right snap {args.right_snap}")
|
||||
if args.no_key_listener: print("Key listener disabled")
|
||||
|
||||
main(args)
|
||||
|
|
36
patterns.py
36
patterns.py
|
@ -159,5 +159,41 @@ id_patterns = {
|
|||
[0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0],
|
||||
]).T,
|
||||
"snap": np.array([
|
||||
[0,0,0,0,0,0,0,0,0],
|
||||
[0,0,0,1,1,1,1,0,0],
|
||||
[0,0,1,0,0,0,0,0,0],
|
||||
[0,0,1,0,0,0,0,0,0],
|
||||
[0,0,0,1,1,1,0,0,0],
|
||||
[0,0,0,0,0,0,1,0,0],
|
||||
[0,0,0,0,0,0,1,0,0],
|
||||
[0,0,1,1,1,1,0,0,0],
|
||||
[0,0,0,0,0,0,0,0,0],
|
||||
[0,0,1,1,0,0,1,0,0],
|
||||
[0,0,1,1,0,0,1,0,0],
|
||||
[0,0,1,0,1,0,1,0,0],
|
||||
[0,0,1,0,1,0,1,0,0],
|
||||
[0,0,1,0,0,1,1,0,0],
|
||||
[0,0,1,0,0,1,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,0,0,0,0,0,0,0],
|
||||
[0,0,0,1,1,1,0,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,1,1,1,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,0,0,0,0,0,0,0],
|
||||
[0,0,1,1,1,1,0,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,0,0,0,1,0,0],
|
||||
[0,0,1,1,1,1,0,0,0],
|
||||
[0,0,1,0,0,0,0,0,0],
|
||||
[0,0,1,0,0,0,0,0,0],
|
||||
[0,0,1,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,0,0]
|
||||
]).T
|
||||
}
|
|
@ -56,9 +56,9 @@ draw_bar = getattr(drawing, 'draw_bar')
|
|||
draw_2_x_1_horiz_grid = getattr(drawing, 'draw_2_x_1_horiz_grid')
|
||||
|
||||
#### Implement low-level drawing functions ####
|
||||
# These functions will be dynamically imported by drawing.py and led_system_monitor.py
|
||||
# These functions will be dynamically imported by drawing.py and called by their correcsponding app function
|
||||
|
||||
metrics_funcs = {
|
||||
direct_draw_funcs = {
|
||||
"temp": {
|
||||
"fn": draw_spiral_vals,
|
||||
"border": draw_8_x_8_grid
|
||||
|
@ -69,8 +69,9 @@ metrics_funcs = {
|
|||
}
|
||||
}
|
||||
|
||||
# Implement app functions that call your high-level draw functions
|
||||
# These functions will be dynamically imported by led_system_monitor.py
|
||||
# Implement app functions that call your direct_draw functions
|
||||
# These functions will be dynamically imported by led_system_monitor.py. They call the direct_draw_funcs
|
||||
# defined above, providing additional capabilities that can be targeted to panel quadrants
|
||||
|
||||
app_funcs = [
|
||||
{
|
||||
|
|
1
snapshot_files/left/left-snap.json
Normal file
1
snapshot_files/left/left-snap.json
Normal file
|
@ -0,0 +1 @@
|
|||
[[0,0,0,1,0,0,0,1,0],[0,0,0,1,0,0,1,0,1],[0,0,0,1,0,0,1,1,1],[0,0,0,1,0,0,1,0,1],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,1,0,0,0,1],[0,0,0,0,1,0,0,0,1],[0,0,0,0,1,0,1,0,1],[0,0,0,0,1,1,1,1,1],[0,0,0,0,1,1,0,1,1],[0,0,0,0,0,0,0,0,0],[1,1,1,1,0,0,1,0,1],[0,1,0,0,0,0,1,0,1],[0,1,0,1,1,0,1,0,1],[0,1,0,1,0,0,1,0,1],[0,1,0,1,0,0,0,1,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,1],[0,0,0,1,0,0,0,1,0],[0,0,1,1,1,0,0,1,0],[0,0,0,1,0,0,0,1,0],[0,0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,0,0],[1,0,0,0,1,0,1,1,1],[1,0,0,0,1,0,1,0,0],[1,0,0,0,1,0,1,1,0],[1,0,0,0,1,0,1,0,0],[1,1,1,0,1,0,1,0,0]]
|
1
snapshot_files/right/right-snap.json
Normal file
1
snapshot_files/right/right-snap.json
Normal file
|
@ -0,0 +1 @@
|
|||
[[1,1,0,1,1,0,0,0,0],[1,1,1,1,1,0,0,0,0],[1,0,1,0,1,0,0,0,0],[1,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,0],[1,0,1,0,1,1,1,0,0],[1,0,1,0,1,0,0,0,0],[1,1,1,0,1,1,0,0,0],[1,0,1,0,1,0,0,0,0],[1,0,1,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0],[0,1,0,0,1,0,1,0,0],[1,0,1,0,1,0,1,0,0],[1,1,1,0,0,1,0,0,0],[1,0,1,0,0,1,0,0,0],[1,0,1,0,0,1,0,0,0],[0,0,0,0,0,0,0,0,0],[1,1,1,0,1,0,1,0,0],[0,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,1,0,0],[0,1,0,0,1,0,1,0,0],[0,1,0,0,1,0,1,0,0],[0,0,0,0,0,0,0,0,0],[1,0,1,0,1,1,1,0,0],[1,0,1,0,1,0,0,0,0],[1,1,1,0,1,1,0,0,0],[1,0,1,0,1,0,0,0,0],[1,0,1,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0],[1,1,1,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0],[1,1,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0],[1,1,1,0,0,0,0,0,0]]
|
Loading…
Add table
Reference in a new issue