-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathled_bars.py
More file actions
executable file
·120 lines (96 loc) · 3.75 KB
/
led_bars.py
File metadata and controls
executable file
·120 lines (96 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python3
"""Display bar graphs on Framework LED matrix modules.
Reads 18 percentage values (0-100) from a file and displays them as
vertical bar graphs on two LED matrix modules (9 columns each).
Optionally reads 18 additional "on"/"off" lines to control the top LED row.
"""
import argparse
import serial
FWK_MAGIC = [0x32, 0xAC]
CMD_STAGE_COL = 0x07
CMD_COMMIT = 0x08
def send_column(ser, col_index, brightness_values):
"""Send 34 brightness values for a single column."""
command = bytes(FWK_MAGIC + [CMD_STAGE_COL, col_index] + brightness_values)
ser.write(command)
def commit_display(ser):
"""Commit staged columns to display."""
command = bytes(FWK_MAGIC + [CMD_COMMIT, 0x00])
ser.write(command)
def percentage_to_column(percent, top_led_on=False, brightness=0xFF):
"""Convert 0-100% to 34-element list with bottom LEDs lit.
Index 0 = top LED (controlled by top_led_on), index 1 = always off.
LEDs light from bottom (33) going up to index 2.
Uses 32 LEDs for percentage display, skipping top 2 rows.
"""
leds_on = round(percent * 32 / 100)
top_led = brightness if top_led_on else 0x00
return [top_led, 0x00] + [brightness if i >= (32 - leds_on) else 0x00 for i in range(32)]
def display_on_device(device_path, percentages, top_leds, brightness=0xFF):
"""Display 9 percentage values on a single device."""
with serial.Serial(device_path, 115200) as ser:
for col, (pct, top_on) in enumerate(zip(percentages, top_leds)):
column_data = percentage_to_column(pct, top_on, brightness)
send_column(ser, col, column_data)
commit_display(ser)
def main():
parser = argparse.ArgumentParser(
description='Display bar graphs on LED matrix modules'
)
parser.add_argument(
'input_file',
help='File with 18 percentage values (0-100), optionally followed by 18 "on"/"off" lines for top LEDs'
)
parser.add_argument(
'--swap-devices',
action='store_true',
help='Swap device order (default: 1-9→ACM1, 10-18→ACM0)'
)
parser.add_argument(
'--device0',
default='/dev/ttyACM0',
help='First device path'
)
parser.add_argument(
'--device1',
default='/dev/ttyACM1',
help='Second device path'
)
parser.add_argument(
'--brightness', '-b',
type=int,
default=255,
help='LED brightness (0-255, default: 255)'
)
args = parser.parse_args()
if not 0 <= args.brightness <= 255:
raise ValueError(f"Brightness must be 0-255, got {args.brightness}")
# Read all lines
with open(args.input_file) as f:
lines = [line.strip() for line in f if line.strip()]
if len(lines) < 18:
raise ValueError(f"Expected at least 18 values, got {len(lines)}")
# Parse percentages (first 18 lines)
values = [int(line) for line in lines[:18]]
# Parse top LED statuses (next 18 lines, optional)
top_leds = []
for i in range(18):
if i + 18 < len(lines) and lines[i + 18].lower() == 'on':
top_leds.append(True)
else:
top_leds.append(False)
# Split values and assign to devices
first_9_pct = values[0:9]
last_9_pct = values[9:18]
first_9_top = top_leds[0:9]
last_9_top = top_leds[9:18]
if args.swap_devices:
device0_pct, device1_pct = first_9_pct, last_9_pct
device0_top, device1_top = first_9_top, last_9_top
else:
device1_pct, device0_pct = first_9_pct, last_9_pct
device1_top, device0_top = first_9_top, last_9_top
display_on_device(args.device0, device0_pct, device0_top, args.brightness)
display_on_device(args.device1, device1_pct, device1_top, args.brightness)
if __name__ == '__main__':
main()