diff --git a/src/controllerSoftware/app.py b/src/controllerSoftware/app.py index fd85e8fe..aa9be298 100644 --- a/src/controllerSoftware/app.py +++ b/src/controllerSoftware/app.py @@ -97,16 +97,24 @@ async def set_full_matrix_on_ble(colorSeries): colorSeries[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: {colorSeries}") - # Write each byte string to its corresponding characteristic - for i, char in enumerate(ble_characteristics): - value_to_write = colorSeries[i] - print(f"Setting Lamp {i} ({char.uuid}) to {value_to_write.hex()}") - await ble_client.write_gatt_char(char.uuid, value_to_write) + if DEBUG_MODE: + # Ensure all characteristics are available before writing + print(f"Confirmed DEBUG set to true.") + 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: {colorSeries}") + # Write each byte string to its corresponding characteristic + for i, char in enumerate(ble_characteristics): + value_to_write = colorSeries[i] + print(f"Setting Lamp {i} ({char.uuid}) to {value_to_write.hex()}") + await ble_client.write_gatt_char(char.uuid, value_to_write) + else: + print(f"Confirmed DEBUG set to false.") + value_to_write = b"".join([color for color in colorSeries]) + print(value_to_write) + print(f"Setting lamps to {value_to_write.hex()}") + await ble_client.write_gatt_char(ble_characteristics[0].uuid, value_to_write) async def connect_to_ble_device(): diff --git a/src/controllerSoftware/run.py b/src/controllerSoftware/run.py deleted file mode 100644 index 1137d79f..00000000 --- a/src/controllerSoftware/run.py +++ /dev/null @@ -1,118 +0,0 @@ -import asyncio -import time -from bleak import BleakScanner, BleakClient - -lampAmount = 25 -LampArray = { - "Center": [0], - "Up": [1,2,8,9,10,11,12,13,23,24], - "Down": [4,5,6,15,16,17,18,19,20,21], - "Left": [6,3,8,9,19,20,21,22,23,12], - "Right": [2,7,4,11,24,13,14,15,16,17], - "Inner": [1,2,3,4,5,6,7,8], - "Outer": [9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24] -} -colorArray = ["500000","005000","000050"] -colorArrayTest = ["050000","000500"] - -def sectionInitializer(): - result = [b'\x00\x00\x00'] * lampAmount - return result - -def sectionSerializer(section, color): - result = sectionInitializer() - sectionResult = LampArray[section] - for pos in sectionResult: - result[pos] = int(color,16).to_bytes(3,'big') - return result - -def posColorByte(pos, section, color): - intColor = int(color, 16) - result = int(intColor * section[pos]) - print(result) - return result.to_bytes(3) - -async def setOnUserInput(client, chars): - while True: - configZone = input("Input Zone [Up, Down, Left, Right, Inner, Outer]: ") - if configZone not in list(LampArray.keys()): - continue - configColor = input("Input Color [000000]: ") - configColorCenter = input("Input Color for Center Lamp [000000]: ") - await setLampToColor(client, chars, configZone, configColor, configColorCenter) - -async def setLampToColor(bleClient, bleChars, section, color, colorCenter): - sectionSerial = sectionSerializer(section, color) - sectionSerial[0] = int(colorCenter,16).to_bytes(3,'big') - for char in bleChars: - 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): - print(f"Scanning for device: {device_name}...") - devices = await BleakScanner.discover() - global services - global client - - target_device = None - for device in devices: - if device.name == device_name: - target_device = device - break - - if target_device: - print(f"Found device: {target_device.name} ({target_device.address})") - async with BleakClient(target_device.address) as client: - if client.is_connected: - print(f"Connected to {target_device.name}") - # Now you can interact with services and characteristics - # Example: Read a characteristic (replace with actual UUID) - # battery_level = await client.read_gatt_char("00002a19-0000-1000-8000-00805f9b34fb") - # print(f"Battery Level: {int.from_bytes(battery_level, 'little')}%") - else: - print(f"Failed to connect to {target_device.name}") - exit(1) - services = sorted(client.services, key=lambda serv: serv.handle) - print("\n--- Services and Characteristics ---") - for service in services: - print(f"\nService: {service.uuid} (Handle: {service.handle}) - {service.description}") - # Get all characteristics for the current service - characteristics = service.characteristics - - # Sort the characteristics by handle - sorted_characteristics = sorted(characteristics, key=lambda char: char.handle) - print("Characteristics sorted by handle:") - for char in sorted_characteristics: - print(f" Characteristic: {char.uuid} (Handle: {char.handle})") - print(f" Description: {char.description}") - print(f" Properties: {char.properties}") - - if "read" in char.properties: - try: - await client.write_gatt_char(char.uuid, bytes.fromhex("000005")) - time.sleep(1) - value = await client.read_gatt_char(char.uuid) - print(f" Value: {value.hex()} (raw bytes)") - except Exception as e: - print(f" Could not read characteristic {char.uuid}: {e}") - else: - print(" (Read not supported)") - -# for color in colorArray: -# await setLampToColor(client, service.characteristics, Up, color) -# await setLampToColor(client, service.characteristics, Down, color) -# await setLampToColor(client, service.characteristics, Left, color) -# await setLampToColor(client, service.characteristics, Right, color) -# await setLampToColor(client, service.characteristics, Inner, color) -# await setLampToColor(client, service.characteristics, Outer, color) - if service.handle != 1: - await setOnUserInput(client, sorted_characteristics) - - else: - print(f"Device '{device_name}' not found.") - -if __name__ == "__main__": - # Replace 'YourDeviceName' with the actual name of your BLE device - asyncio.run(connect_to_ble_device("Pupilometer LED Billboard")) diff --git a/src/controllerSoftware/templates/index.html b/src/controllerSoftware/templates/index.html index e6c5b32f..a1efb11b 100644 --- a/src/controllerSoftware/templates/index.html +++ b/src/controllerSoftware/templates/index.html @@ -196,12 +196,29 @@ $('.region-slider-group input').on('input', function() { if (selectedLamps.length === 0) return; + var target = $(this); + var originalVal = target.val(); + var value = parseInt(originalVal, 10); + + // Clamp value + if (isNaN(value) || value < 0) { value = 0; } + if (value > 255) { value = 255; } + + if (target.is('[type="number"]') && value.toString() !== originalVal) { + target.val(value); + } + + var id = target.attr('id'); + if (target.is('[type="range"]')) { + $(`#${id.replace('-slider', '-number')}`).val(value); + } else if (target.is('[type="number"]')) { + $(`#${id.replace('-number', '-slider')}`).val(value); + } + var ww = parseInt($('#ww-slider').val()); var cw = parseInt($('#cw-slider').val()); var blue = parseInt($('#blue-slider').val()); - updateSliders(ww, cw, blue, ''); - var lampsToUpdate = []; selectedLamps.forEach(function(lamp) { lampMatrixState[lamp.row][lamp.col] = {ww: ww, cw: cw, blue: blue}; @@ -213,12 +230,29 @@ // Event listener for the center lamp sliders and number inputs $('.center-slider-group input').on('input', function() { + var target = $(this); + var originalVal = target.val(); + var value = parseInt(originalVal, 10); + + // Clamp value + if (isNaN(value) || value < 0) { value = 0; } + if (value > 255) { value = 255; } + + if (target.is('[type="number"]') && value.toString() !== originalVal) { + target.val(value); + } + + var id = target.attr('id'); + if (target.is('[type="range"]')) { + $(`#${id.replace('-slider', '-number')}`).val(value); + } else if (target.is('[type="number"]')) { + $(`#${id.replace('-number', '-slider')}`).val(value); + } + var ww = parseInt($('#center-ww-slider').val()); var cw = parseInt($('#center-cw-slider').val()); var blue = parseInt($('#center-blue-slider').val()); - updateSliders(ww, cw, blue, 'center-'); - var centerLamp = {row: 2, col: 2}; lampMatrixState[centerLamp.row][centerLamp.col] = {ww: ww, cw: cw, blue: blue}; diff --git a/src/controllerSoftware/web.py b/src/controllerSoftware/web.py deleted file mode 100644 index 804d661e..00000000 --- a/src/controllerSoftware/web.py +++ /dev/null @@ -1,130 +0,0 @@ -from flask import Flask, render_template, request, jsonify - -# ... (paste the two helper functions here if they are not already present) ... - -app = Flask(__name__) - -def create_spiral_map(n=5): - """ - Creates a pre-computed spiral mapping for an n x n matrix. - The spiral starts from the center, moves up, then right, and spirals outwards. - - Args: - n (int): The size of the square matrix. - - Returns: - list of lists: A 2D list where each element is the spiraling address. - """ - if n % 2 == 0: - raise ValueError("Matrix size must be odd for a unique center point.") - - spiral_map = [[0] * n for _ in range(n)] - - # Starting position and index - r, c = n // 2, n // 2 - address = 0 - spiral_map[r][c] = address - - # Directions: Up, Right, Down, Left - # This is the key change to adjust the spiral path - dr = [-1, 0, 1, 0] - dc = [0, 1, 0, -1] - direction = 0 - - segment_length = 1 - steps = 0 - - while address < n * n - 1: - for _ in range(segment_length): - address += 1 - r += dr[direction] - c += dc[direction] - if 0 <= r < n and 0 <= c < n: - spiral_map[r][c] = address - - direction = (direction + 1) % 4 - steps += 1 - - if steps % 2 == 0: - segment_length += 1 - - return spiral_map - -def get_spiral_address(row, col, spiral_map): - """ - Converts a standard (row, col) address to a spiraling address - using a pre-computed map. - - Args: - row (int): The row index (0-indexed). - col (int): The column index (0-indexed). - spiral_map (list of lists): The pre-computed spiral map. - - Returns: - int: The spiraling address, or -1 if the coordinates are out of bounds. - """ - n = len(spiral_map) - if 0 <= row < n and 0 <= col < n: - return spiral_map[row][col] - else: - return -1 - -# Pre-compute the spiral map for a 5x5 matrix when the app starts -SPIRAL_MAP_5x5 = create_spiral_map(5) - -# Initialize a 5x5 matrix with all lamps off (black color code) -lamp_matrix = [['#000000' for _ in range(5)] for _ in range(5)] - -# Define a helper function to convert hex to RGB for template use -def hex_to_rgb(hex_color): - hex_color = hex_color.lstrip('#') - return { - 'r': int(hex_color[0:2], 16), - 'g': int(hex_color[2:4], 16), - 'b': int(hex_color[4:6], 16) - } - -app.jinja_env.globals.update(hex_to_rgb=hex_to_rgb) - -@app.route('/') -def index(): - """ - Renders the main control interface for the RGB lamp matrix. - """ - return render_template('index.html', matrix=lamp_matrix) - -@app.route('/set_color', methods=['POST']) -def set_color(): - """ - Sets the color for multiple lamps and turns all others black. - """ - data = request.get_json() - lamps_to_update = data.get('lamps', []) - r = data.get('r') - g = data.get('g') - b = data.get('b') - - try: - r, g, b = int(r), int(g), int(b) - new_color = '#{:02x}{:02x}{:02x}'.format(r, g, b) - - # First, turn all lamps black - for row in range(5): - for col in range(5): - lamp_matrix[row][col] = '#000000' - - # Then, apply the new color to the selected lamps - for lamp in lamps_to_update: - row = lamp['row'] - col = lamp['col'] - if 0 <= row < 5 and 0 <= col < 5: - lamp_matrix[row][col] = new_color - print(get_spiral_address(row, col, SPIRAL_MAP_5x5)) - - return jsonify(success=True, new_color=new_color) - - except (ValueError, TypeError, IndexError): - return jsonify(success=False, message="Invalid data received") - -if __name__ == '__main__': - app.run(debug=True,host='0.0.0.0') diff --git a/src/lightingFirmware/SimpleBleDevice/SimpleBleDevice.ino b/src/lightingFirmware/SimpleBleDevice/SimpleBleDevice.ino deleted file mode 100644 index 45cfc64f..00000000 --- a/src/lightingFirmware/SimpleBleDevice/SimpleBleDevice.ino +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include -#include - -BLEServer* pServer = NULL; -BLECharacteristic* pCharacteristic = NULL; -bool deviceConnected = false; -bool oldDeviceConnected = false; -uint32_t value = 0; -String btmessage; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ - -#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" -#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" - - -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - deviceConnected = true; - }; - - void onDisconnect(BLEServer* pServer) { - deviceConnected = false; - } -}; - - - -void setup() { - Serial.begin(115200); - - // Create the BLE Device - BLEDevice::init("ESP32"); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService(SERVICE_UUID); - - // Create a BLE Characteristic - pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID, - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_INDICATE - ); - - // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml - // Create a BLE Descriptor - pCharacteristic->addDescriptor(new BLE2902()); - - // Start the service - pService->start(); - - // Start advertising - BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_UUID); - pAdvertising->setScanResponse(false); - pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter - BLEDevice::startAdvertising(); - Serial.println("Waiting a client connection to notify..."); -} - -void loop() { - // notify changed value - if (deviceConnected) { - btmessage = pCharacteristic->getData(); - mode = btmessage; - } - // disconnecting - if (!deviceConnected && oldDeviceConnected) { - delay(500); // give the bluetooth stack the chance to get things ready - pServer->startAdvertising(); // restart advertising - Serial.println("Start advertising"); - oldDeviceConnected = deviceConnected; - } - // connecting - if (deviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = deviceConnected; - } -} \ No newline at end of file diff --git a/src/lightingFirmware/SimpleBleDevice/ci.json b/src/lightingFirmware/SimpleBleDevice/ci.json deleted file mode 100644 index d33a23f3..00000000 --- a/src/lightingFirmware/SimpleBleDevice/ci.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "requires": [ - "CONFIG_BT_ENABLED=y", - "CONFIG_BLUEDROID_ENABLED=y" - ] -} diff --git a/src/lightingFirmware/esp32_test0/esp32_test0.ino b/src/lightingFirmware/esp32_test0/esp32_test0.ino index cc657f83..d7c6707b 100644 --- a/src/lightingFirmware/esp32_test0/esp32_test0.ino +++ b/src/lightingFirmware/esp32_test0/esp32_test0.ino @@ -15,6 +15,8 @@ bool debugMode = true; int bleCharCount; const int channelPerLamp = 4; +const int expectedLampCount = 25; +const int dmxPacketSize = channelPerLamp * expectedLampCount + 1; // struct Button { const uint8_t PIN; @@ -26,7 +28,6 @@ BLEServer* pServer = NULL; bool deviceConnected = false; bool oldDeviceConnected = false; -uint32_t value = 0; uint16_t SERVICE_UUID = 20241115; const int panelAmount = 25; @@ -286,22 +287,22 @@ void setup() { // Create the BLE Service BLEService *pService = pServer->createService(SERVICE_UUID,52); - const bool debugMode = true; + const bool debugMode = false; // Serial.printf(debugMode); // Create a BLE Characteristic Serial.printf("\nCalculating BLE Charateristic Count"); bleCharCount = (panelAmount * debugMode) + !debugMode; - Serial.printf("\nCalculating BLE MTU"); + Serial.printf("\nCalculating BLE MTU ..."); uint16_t bleMTU = ((panelAmount * 3) / bleCharCount) + 3; - // Serial.printf("\nSetting BLE MTU to %i bytes... ", bleMTU); - // BLEDevice::setMTU(bleMTU + 3); + Serial.printf("\nSetting BLE MTU to %i bytes... ", bleMTU); + BLEDevice::setMTU(bleMTU + 3); Serial.printf("Done!\n"); for (uint32_t i = 0; i < bleCharCount; i++){ - UUID uuid; - uuid.seed(i+1); - uuid.generate(); - Serial.printf("Creating BLE Characteristic with UUID %s ...", uuid.toCharArray()); + //UUID uuid; + //uuid.seed(i+1); + //uuid.generate(); + //Serial.printf("Creating BLE Characteristic with UUID %s ...", BLEUUID(i+1)); pCharacteristics[i] = pService->createCharacteristic( i+1, @@ -311,8 +312,10 @@ void setup() { BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE ); + Serial.printf("Created BLE Characteristic with UUID %s ...", pCharacteristics[i]->getUUID().toString().c_str()); + // pCharacteristics[i]->addDescriptor(new BLE2902()); - Serial.printf("Done\n"); +// Serial.printf("Done\n"); }; // Start the service @@ -332,17 +335,10 @@ void loop() { int modeOld = mode; int msgSize; uint8_t* btMessage[bleCharCount]; + // uint8_t dmxData[DMX_PACKET_SIZE] = {0}; // notify changed value if (deviceConnected) { - for (int i = 0; i < bleCharCount;i++){ - btMessage[i] = pCharacteristics[i]->getData(); - msgSize = pCharacteristics[i]->getLength(); - Serial.printf("\nI have received %i bytes.", msgSize); - //for (int j = 0; j < msgSize; j++){ - // Serial.printf("[%i - %d] ",j,btMessage[i][j]); - //}; - //Serial.printf("\n"); - } + } // disconnecting if (!deviceConnected && oldDeviceConnected) { @@ -357,40 +353,49 @@ void loop() { oldDeviceConnected = deviceConnected; } - serialRead(); +// Serial.printf("\nConstructing Payload using "); +// Serial.printf("Bluetooth Data ..."); if (button1.pressed){ if (mode < modeAmount - 1){mode++;} else {mode = 0;}; // Increment the value of each slot, excluding the start code. button1.pressed = false; // Reset button status to FALSE }; -// Serial.printf("\nConstructing Payload using "); - if (deviceConnected){ -// Serial.printf("Bluetooth Data ..."); - Serial.printf("\nConstructing DMX Payload: "); - for (int i = 0; i < bleCharCount; i++){ - for (int j = 0; j < msgSize; j++){ - int packet = btMessage[i][j]; - int k = i*3 + j; - int dmxAddress = (k / 3) * 4 + k % 3 + 1; - dmxData[dmxAddress] = packet; - Serial.printf("[[%i,%i] %i - %i] ",i , j, dmxAddress, packet); - }; + serialRead(); + if (modeOld != mode){ + Serial.printf("\nChanging Lighting Preset to Preset %d", mode); + uint8_t lampData[DMX_PACKET_SIZE / 4 * 3]; + Serial.printf("\nDetected preset %i size: %i", mode, sizeof(dataSeq[mode])); + for (int i = 0; i < sizeof(dataSeq[mode]); i++){ + dmxData[i] = dataSeq[mode][i]; + int sublampIndex = i % 4; + //Serial.printf("[%i]", sublampIndex, j); + if (sublampIndex > 0) { + int j = (i / 4) * 3 + sublampIndex - 1; + Serial.printf("[%i](%i)", j, sublampIndex); + lampData[j] = dataSeq[mode][i]; + } }; - Serial.printf("\n"); + pCharacteristics[0]->setValue(lampData, expectedLampCount * 3); } - else{ -// Serial.printf("Preset Data ..."); - if (modeOld != mode){ - Serial.printf("\nChanging Lighting Preset to Preset %d", mode); - for (int i = 0; i < sizeof(dataSeq[mode]); i++){ - dmxData[i] = dataSeq[mode][i]; - }; - } + Serial.printf("\nConstructing DMX Payload with size "); + for (int i = 0; i < bleCharCount; i++){ + btMessage[i] = pCharacteristics[i]->getData(); + msgSize = pCharacteristics[i]->getLength(); + Serial.printf("%i bytes ", msgSize); + for (int j = 0; j < msgSize; j++){ + int packet = btMessage[i][j]; + int lampSum = i*3 + j; + int dmxAddress = (lampSum / 3) * 4 + lampSum % 3 + 1; + dmxData[dmxAddress] = packet; + // Serial.printf("[[%i,%i] %i - %i] ",i , j, dmxAddress, packet); + }; }; + Serial.printf("\n"); + // Serial.printf(" Done"); // Wait until the packet is finished being sent before proceeding. dmx_wait_sent(DMX_NUM_1, DMX_TIMEOUT_TICK); // Now write the packet synchronously! - dmx_write(DMX_NUM_1, dmxData, 100); + dmx_write(DMX_NUM_1, dmxData, DMX_PACKET_SIZE); dmx_send(DMX_NUM_1); }