diff --git a/src/controllerSoftware/app.py b/src/controllerSoftware/app.py index a6f000e..35a7879 100644 --- a/src/controllerSoftware/app.py +++ b/src/controllerSoftware/app.py @@ -3,6 +3,7 @@ import asyncio from bleak import BleakScanner, BleakClient import threading import time +import json # ================================================================================================= # APP CONFIGURATION @@ -10,7 +11,7 @@ import time # Set to True to run without a physical BLE device for testing purposes. # Set to False to connect to the actual lamp matrix. -DEBUG_MODE = True +DEBUG_MODE = False # --- BLE Device Configuration (Ignored in DEBUG_MODE) --- DEVICE_NAME = "Pupilometer LED Billboard" @@ -33,8 +34,11 @@ def create_spiral_map(n=5): r, c = n // 2, n // 2 address = 0 spiral_map[r][c] = address - dr = [0, 1, 0, -1] - dc = [1, 0, -1, 0] + + # Updated directions to start moving UP first instead of right + dr = [-1, 0, 1, 0] # Change in row: Up, Right, Down, Left + dc = [0, 1, 0, -1] # Change in col: Up, Right, Down, Left + direction = 0 segment_length = 1 steps = 0 @@ -51,6 +55,7 @@ def create_spiral_map(n=5): segment_length += 1 return spiral_map + def get_spiral_address(row, col, spiral_map): n = len(spiral_map) if 0 <= row < n and 0 <= col < n: @@ -60,7 +65,7 @@ def get_spiral_address(row, col, spiral_map): SPIRAL_MAP_5x5 = create_spiral_map(5) -async def set_lamp_colors_on_ble(lamps_to_update, new_color): +async def set_full_matrix_on_ble(full_matrix): global ble_client global ble_characteristics @@ -70,32 +75,55 @@ async def set_lamp_colors_on_ble(lamps_to_update, new_color): if not ble_client or not ble_client.is_connected: print("Failed to reconnect to BLE client.") return + else: + print("Confirmed BLE connection status. Proceeding with lamp update.") - # Create a full matrix of colors to send + print("Initializing blank canvas...") serial_colors = [b'\x00\x00\x00'] * lampAmount - center_lamp_color = b'\x00\x00\x00' - center_pos = get_spiral_address(2, 2, SPIRAL_MAP_5x5) + print(f"Initialized: {serial_colors}") - # Note: A real implementation would query the device for the center lamp's current color - # to maintain persistence. For simplicity in this example, we'll assume it's set to black initially. - # We will update this logic later if needed. + for row in range(5): + for col in range(5): - # Apply all other lamps to black - for char_index in range(lampAmount): - if char_index != center_pos: - serial_colors[char_index] = b'\x00\x00\x00' + lamp_data = full_matrix[row][col] + print(f"Construcing lamp {row},{col} data: {lamp_data}") + ww = int(lamp_data['ww']) + cw = int(lamp_data['cw']) + blue = int(lamp_data['blue']) - # Apply the new color to the selected lamps - for lamp in lamps_to_update: - spiral_pos = get_spiral_address(lamp['row'], lamp['col'], SPIRAL_MAP_5x5) - if spiral_pos != -1: - serial_colors[spiral_pos] = new_color + color_bytes = bytes([ww, cw, blue]) + spiral_pos = get_spiral_address(row, col, SPIRAL_MAP_5x5) + print(f"Constructed data for {spiral_pos}: {color_bytes}") + if spiral_pos != -1: + serial_colors[spiral_pos] = color_bytes + # ===================================================================== + # SNIPPET TO PATCH SWAPPED LAMP POSITIONS + # ===================================================================== + print("Patching lamp positions 3 <-> 7 and 12 <-> 24.") + + # Swap data for lamps at positions 3 and 7 + temp_color_3 = serial_colors[3] + serial_colors[3] = serial_colors[7] + serial_colors[7] = temp_color_3 + + # Swap data for lamps at positions 12 and 24 + temp_color_12 = serial_colors[12] + serial_colors[12] = serial_colors[24] + serial_colors[24] = temp_color_12 + # ===================================================================== + + # Ensure all characteristics are available before writing + if len(ble_characteristics) != lampAmount: + print(f"Mismatch in lamp amount. Expected {lampAmount}, got {len(ble_characteristics)}.") + return + print(f"Constructed the following matrix data: {serial_colors}") # Write each byte string to its corresponding characteristic for i, char in enumerate(ble_characteristics): value_to_write = serial_colors[i] + print(f"Setting Lamp {i} ({char.uuid}) to {value_to_write.hex()}") await ble_client.write_gatt_char(char.uuid, value_to_write) - print(f"Setting Lamp {i} to {value_to_write.hex()}") + async def connect_to_ble_device(): global ble_client @@ -116,11 +144,12 @@ async def connect_to_ble_device(): await ble_client.connect() if ble_client.is_connected: print(f"Connected to {target_device.name}") - services = await ble_client.get_services() - ble_characteristics = sorted([ + services = ble_client.services + # The previous logic for filtering services seems incorrect; let's grab all characteristics + characteristics = [ char for service in services for char in service.characteristics - ], key=lambda char: char.handle)[:lampAmount] - + ] + ble_characteristics = sorted(characteristics, key=lambda char: char.handle) print(f"Found {len(ble_characteristics)} characteristics for lamps.") return True else: @@ -145,60 +174,49 @@ def index(): return render_template('index.html', matrix=lamp_matrix) else: # In live mode, we'll pass a default black matrix. - # The true state is on the device. initial_matrix = [['#000000' for _ in range(5)] for _ in range(5)] return render_template('index.html', matrix=initial_matrix) -@app.route('/set_color', methods=['POST']) -# Updated part of your app.py -@app.route('/set_color', methods=['POST']) -def set_color(): +@app.route('/set_matrix', methods=['POST']) +def set_matrix(): data = request.get_json() - lamps_to_update = data.get('lamps', []) - r = data.get('ww') - g = data.get('cw') - b = data.get('blue') + full_matrix = data.get('matrix', []) - if not lamps_to_update: - return jsonify(success=False, message="No lamps selected") + if not full_matrix or len(full_matrix) != 5 or len(full_matrix[0]) != 5: + return jsonify(success=False, message="Invalid matrix data received"), 400 + else: + print(f"Received the following matrix data: {full_matrix}") + try: - r, g, b = int(r), int(g), int(b) - new_color_hex = f'#{r:02x}{g:02x}{b:02x}' - if DEBUG_MODE: # === DEBUG MODE: Update in-memory matrix === - center_row, center_col = 2, 2 - center_lamp_color = lamp_matrix[center_row][center_col] - - # First, turn all non-center lamps black for row in range(5): for col in range(5): - if (row, col) != (center_row, center_col): - lamp_matrix[row][col] = '#000000' - - # Apply the new color to the selected lamps - for lamp in lamps_to_update: - lamp_matrix[lamp['row']][lamp['col']] = new_color_hex - - # The center lamp is handled by its own controls, so it remains persistent - # unless it's part of a region update. We re-apply its color here. - # No, we don't. The logic is that it gets reset unless it's selected. - - return jsonify(success=True, new_color=new_color_hex) + lamp_data = full_matrix[row][col] + ww = lamp_data['ww'] + cw = lamp_data['cw'] + blue = lamp_data['blue'] + + # Convert ww, cw, blue to a hex color for UI display + r = min(255, ww + cw) + g = min(255, ww + cw + blue) + b = min(255, blue + cw) + new_color_hex = f'#{r:02x}{g:02x}{b:02x}' + lamp_matrix[row][col] = new_color_hex + + return jsonify(success=True) else: # === LIVE MODE: Communicate with the BLE device === - new_color_bytes = int(f'{r:02x}{g:02x}{b:02x}', 16).to_bytes(3, 'big') - asyncio.run_coroutine_threadsafe( - set_lamp_colors_on_ble(lamps_to_update, new_color_bytes), + set_full_matrix_on_ble(full_matrix), ble_event_loop ) - return jsonify(success=True, new_color=new_color_hex) + return jsonify(success=True) except Exception as e: - print(f"Error in set_color route: {e}") + print(f"Error in set_matrix route: {e}") return jsonify(success=False, message=str(e)), 500 # ================================================================================================= diff --git a/src/controllerSoftware/run.py b/src/controllerSoftware/run.py index 3e4393f..1137d79 100644 --- a/src/controllerSoftware/run.py +++ b/src/controllerSoftware/run.py @@ -48,7 +48,6 @@ async def setLampToColor(bleClient, bleChars, section, color, colorCenter): lampPos = bleChars.index(char) value = sectionSerial[lampPos] print(f"Setting Lamp number {lampPos} to {value}") - await bleClient.write_gatt_char(char.uuid, value) async def connect_to_ble_device(device_name): diff --git a/src/controllerSoftware/templates/index.html b/src/controllerSoftware/templates/index.html index 11686bd..a423747 100644 --- a/src/controllerSoftware/templates/index.html +++ b/src/controllerSoftware/templates/index.html @@ -2,142 +2,96 @@