diff --git a/drawing.py b/drawing.py index c49db51..c5cfe2b 100644 --- a/drawing.py +++ b/drawing.py @@ -1,3 +1,6 @@ +import time +import math + import numpy as np import serial @@ -59,6 +62,23 @@ lookup_table = np.array( ] ] ) + +lightning_bolt = np.array( [[0,0,0,0,0,0,0], # 0 + [0,0,0,0,0,1,0], # 1 + [0,0,0,0,1,1,0], # 2 + [0,0,0,1,1,0,0], # 3 + [0,0,1,1,1,0,0], # 4 + [0,1,1,1,0,0,0], # 5 + [0,1,1,1,1,1,0], # 6 + [0,0,0,1,1,1,0], # 7 + [0,0,1,1,1,0,0], # 8 + [0,0,1,1,0,0,0], # 9 + [0,1,1,0,0,0,0], #10 + [0,1,0,0,0,0,0], #11 + [0,0,0,0,0,0,0]],#12 + dtype=bool).T + + # Correct table orientation for visual orientation when drawn for i in range(lookup_table.shape[0]): lookup_table[i] = lookup_table[i].T @@ -67,24 +87,58 @@ for i in range(lookup_table.shape[0]): def spiral_index(fill_ratio): return int(round(fill_ratio * 9.999999 - 0.5)) -def make_cpu_grid(cpu_values, border_value, fill_value): - grid = np.zeros((9,34), dtype = int) +# Takes up 15 rows, 7 columns, starting at 1,1 +def draw_cpu(grid, cpu_values, fill_value): for i, v in enumerate(cpu_values): column_number = i % 2 row_number = i // 2 fill_grid = lookup_table[spiral_index(v)] grid[1+column_number*4:4+column_number*4, 1+row_number*4:4+row_number*4] = fill_grid * fill_value + +# Takes up 2 rows, 7 columns, starting at 17,1 +def draw_memory(grid, memory_ratio, fill_value): + lit_pixels = 7 * 2 * memory_ratio + pixels_bottom = int(round(lit_pixels / 2)) + pixels_top = int(round((lit_pixels - 0.49) / 2)) + grid[1:1+pixels_top,17] = fill_value + grid[1:1+pixels_bottom,18] = fill_value + +# Takes up 13 rows, 7 columns, starting at 21,1 +def draw_battery(grid, battery_ratio, battery_plugged, fill_value, battery_low_thresh = 0.07, battery_low_flash_time = 2, charging_pulse_time = 3): + lit_pixels = int(round(13 * 7 * battery_ratio)) + pixels_base = lit_pixels // 7 + remainder = lit_pixels % 7 + if battery_ratio <= battery_low_thresh and not battery_plugged: + if time.time() % battery_low_flash_time * 2 < battery_low_flash_time: # This will flash the battery indicator if too low + return + for i in range(7): + pixels_col = pixels_base + if i <= remainder: + pixels_col += 1 + grid[i+1,33-pixels_col:33] = fill_value + if battery_plugged: + pulse_amount = math.sin(time.time() / charging_pulse_time) + grid[1:8,20:33][lightning_bolt] -= np.rint(fill_value + 10 * pulse_amount).astype(int) + indices = grid[1:8,20:33] < 0 + grid[1:8,20:33][indices] = -grid[1:8,20:33][indices] + +def draw_borders(grid, border_value): # Fill in the borders - grid[0, :16] = border_value + # Cpu vertical partitions grid[4, :16] = border_value - grid[8, :16] = border_value - grid[:, 0] = border_value + # Cpu horizontal partitions grid[:, 4] = border_value grid[:, 8] = border_value grid[:, 12] = border_value grid[:, 16] = border_value - return grid + # Memory bottom partition + grid[:, 19] = border_value + # Outer Edge borders + grid[:, 0] = border_value # Top + grid[0, :] = border_value # Left + grid[8, :] = border_value # Right + grid[:, 33] = border_value # Bottom def draw_to_LEDs(s, grid): for i in range(grid.shape[0]): @@ -95,7 +149,14 @@ def draw_to_LEDs(s, grid): if __name__ == "__main__": # LED array is 34x9, and is indexed left to right top to bottom - grid = make_cpu_grid([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8], 10, 30) port = "COM3" with serial.Serial(port, 115200) as s: - draw_to_LEDs(s, grid) \ No newline at end of file + while True: + grid = np.zeros((9,34), dtype = int) + draw_cpu(grid, [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8], 30) + draw_memory(grid, 0.3, 30) + draw_battery(grid, 0.75, True, 30) + draw_borders(grid, 10) + print(grid.T) + draw_to_LEDs(s, grid) + time.sleep(0.05) \ No newline at end of file diff --git a/led_system_monitor.py b/led_system_monitor.py index d8ffe6e..376faf1 100644 --- a/led_system_monitor.py +++ b/led_system_monitor.py @@ -6,8 +6,8 @@ import queue # Internal Dependencies from commands import Commands, send_command -from drawing import make_cpu_grid, draw_to_LEDs -from monitors import CPUMonitorThread +from drawing import draw_cpu, draw_memory, draw_battery, draw_borders, draw_to_LEDs +from monitors import CPUMonitorThread, MemoryMonitorThread, BatteryMonitorThread # External Dependencies try: @@ -62,21 +62,42 @@ if __name__ == "__main__": cpu_monitor = CPUMonitorThread(cpu_queue) cpu_monitor.start() + memory_queue = queue.Queue(2) + memory_monitor = MemoryMonitorThread(memory_queue) + memory_monitor.start() + + battery_queue = queue.Queue(2) + battery_monitor = BatteryMonitorThread(battery_queue) + battery_monitor.start() + s = serial.Serial(port, 115200) - min_background_brightness = 10 - max_background_brightness = 30 + min_background_brightness = 8 + max_background_brightness = 20 min_foreground_brightness = 30 - max_foreground_brightness = 120 + max_foreground_brightness = 110 + + last_cpu_values = cpu_queue.get() + last_memory_values = memory_queue.get() + last_battery_values = battery_queue.get() while True: if not cpu_queue.empty(): - cpu_values = cpu_queue.get() - screen_brightness = sbc.get_brightness()[0] - background_value = int(screen_brightness / 100 * (max_background_brightness - min_background_brightness) + min_background_brightness) - foreground_value = int(screen_brightness / 100 * (max_foreground_brightness - min_foreground_brightness) + min_foreground_brightness) - grid = make_cpu_grid(cpu_values, background_value, foreground_value) - draw_to_LEDs(s, grid) + last_cpu_values = cpu_queue.get() + if not memory_queue.empty(): + last_memory_values = memory_queue.get() + if not battery_queue.empty(): + last_battery_values = battery_queue.get() + + screen_brightness = sbc.get_brightness()[0] + background_value = int(screen_brightness / 100 * (max_background_brightness - min_background_brightness) + min_background_brightness) + foreground_value = int(screen_brightness / 100 * (max_foreground_brightness - min_foreground_brightness) + min_foreground_brightness) + grid = np.zeros((9,34), dtype = int) + draw_cpu(grid, last_cpu_values, foreground_value) + draw_memory(grid, last_memory_values, foreground_value) + draw_battery(grid, last_battery_values[0], last_battery_values[1], foreground_value) + draw_borders(grid, background_value) + draw_to_LEDs(s, grid) time.sleep(0.05) diff --git a/monitors.py b/monitors.py index b39cc74..c0902f6 100644 --- a/monitors.py +++ b/monitors.py @@ -141,38 +141,61 @@ class MemoryMonitorThread(threading.Thread): self.output_queue.put(avg_memory_usage) time.sleep(self.update_interval) +class BatteryMonitorThread(threading.Thread): + def __init__(self, output_queue, update_interval = 1): + super().__init__() + self.daemon = True + self.update_interval = update_interval + self.output_queue = output_queue + + def run(self): + while True: + if not self.output_queue.full(): + battery = psutil.sensors_battery() + if battery is not None: + battery_percentage = battery.percent / 100.0 + battery_plugged = battery.power_plugged + self.output_queue.put((battery_percentage, battery_plugged)) + time.sleep(self.update_interval) if __name__ == "__main__": disk_queue = queue.Queue() network_queue = queue.Queue() cpu_queue = queue.Queue() memory_queue = queue.Queue() + battery_queue = queue.Queue() disk_monitor = DiskMonitorThread(disk_queue) network_monitor = NetworkMonitorThread(network_queue) cpu_monitor = CPUMonitorThread(cpu_queue) memory_monitor = MemoryMonitorThread(memory_queue) + battery_monitor = BatteryMonitorThread(battery_queue) disk_monitor.start() network_monitor.start() cpu_monitor.start() memory_monitor.start() + battery_monitor.start() while True: if not disk_queue.empty(): read_percent, write_percent = disk_queue.get() - print(f"Disk Usage: Read {read_percent:.2%}, Write {write_percent:.2%}") + print(f"Disk: Read {read_percent:.2%}, Write {write_percent:.2%}") if not network_queue.empty(): sent_percent, recv_percent = network_queue.get() - print(f"Network Usage: Sent {sent_percent:.2%}, Received {recv_percent:.2%}") + print(f"Network: Sent {sent_percent:.2%}, Received {recv_percent:.2%}") if not cpu_queue.empty(): cpu_percentages = cpu_queue.get() - print(f"CPU Usage: {cpu_percentages}") + print(f"CPU: {cpu_percentages}") if not memory_queue.empty(): memory_usage = memory_queue.get() - print(f"Memory Usage: {memory_usage:.2%}") + print(f"Memory: {memory_usage:.2%}") + + if not battery_queue.empty(): + battery_percentage, battery_plugged = battery_queue.get() + print(f"Battery: {battery_percentage:.2%}, Plugged: {battery_plugged}") time.sleep(0.5) \ No newline at end of file