Corrected the web page behavior on widescreen to get matrix and control panel side by side.

This commit is contained in:
Tempest 2025-08-08 15:16:47 +07:00
parent 1819bbfa2e
commit 89677ac283
3 changed files with 111 additions and 81 deletions

View File

@ -11,7 +11,7 @@ import json
# Set to True to run without a physical BLE device for testing purposes. # Set to True to run without a physical BLE device for testing purposes.
# Set to False to connect to the actual lamp matrix. # Set to False to connect to the actual lamp matrix.
DEBUG_MODE = True DEBUG_MODE = False
# --- BLE Device Configuration (Ignored in DEBUG_MODE) --- # --- BLE Device Configuration (Ignored in DEBUG_MODE) ---
DEVICE_NAME = "Pupilometer LED Billboard" DEVICE_NAME = "Pupilometer LED Billboard"
@ -65,7 +65,7 @@ def get_spiral_address(row, col, spiral_map):
SPIRAL_MAP_5x5 = create_spiral_map(5) SPIRAL_MAP_5x5 = create_spiral_map(5)
async def set_full_matrix_on_ble(serial_colors): async def set_full_matrix_on_ble(colorSeries):
global ble_client global ble_client
global ble_characteristics global ble_characteristics
@ -84,24 +84,24 @@ async def set_full_matrix_on_ble(serial_colors):
print("Patching lamp positions 3 <-> 7 and 12 <-> 24.") print("Patching lamp positions 3 <-> 7 and 12 <-> 24.")
# Swap data for lamps at positions 3 and 7 # Swap data for lamps at positions 3 and 7
temp_color_3 = serial_colors[3] temp_color_3 = colorSeries[3]
serial_colors[3] = serial_colors[7] colorSeries[3] = colorSeries[7]
serial_colors[7] = temp_color_3 colorSeries[7] = temp_color_3
# Swap data for lamps at positions 12 and 24 # Swap data for lamps at positions 12 and 24
temp_color_12 = serial_colors[12] temp_color_12 = colorSeries[12]
serial_colors[12] = serial_colors[24] colorSeries[12] = colorSeries[24]
serial_colors[24] = temp_color_12 colorSeries[24] = temp_color_12
# ===================================================================== # =====================================================================
# Ensure all characteristics are available before writing # Ensure all characteristics are available before writing
if len(ble_characteristics) != lampAmount: if len(ble_characteristics) != lampAmount:
print(f"Mismatch in lamp amount. Expected {lampAmount}, got {len(ble_characteristics)}.") print(f"Mismatch in lamp amount. Expected {lampAmount}, got {len(ble_characteristics)}.")
return return
print(f"Constructed the following matrix data: {serial_colors}") print(f"Constructed the following matrix data: {colorSeries}")
# Write each byte string to its corresponding characteristic # Write each byte string to its corresponding characteristic
for i, char in enumerate(ble_characteristics): for i, char in enumerate(ble_characteristics):
value_to_write = serial_colors[i] value_to_write = colorSeries[i]
print(f"Setting Lamp {i} ({char.uuid}) to {value_to_write.hex()}") print(f"Setting Lamp {i} ({char.uuid}) to {value_to_write.hex()}")
await ble_client.write_gatt_char(char.uuid, value_to_write) await ble_client.write_gatt_char(char.uuid, value_to_write)
@ -159,9 +159,9 @@ def calculate_rgb(ww, cw, blue):
b = (ww / 255) * warm_white_b + (cw / 255) * cool_white_b + (blue / 255) * blue_b b = (ww / 255) * warm_white_b + (cw / 255) * cool_white_b + (blue / 255) * blue_b
# Clamp the values to 255 and convert to integer # Clamp the values to 255 and convert to integer
r = min(255, round(r)) r = int(min(255, round(r)))
g = min(255, round(g)) g = int(min(255, round(g)))
b = min(255, round(b)) b = int(min(255, round(b)))
return r, g, b return r, g, b
@ -233,7 +233,7 @@ def set_matrix():
else: else:
# === LIVE MODE: Communicate with the BLE device === # === LIVE MODE: Communicate with the BLE device ===
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
set_full_matrix_on_ble(full_matrix), set_full_matrix_on_ble(serial_colors),
ble_event_loop ble_event_loop
) )
return jsonify(success=True) return jsonify(success=True)

View File

@ -18,6 +18,12 @@ body {
align-items: center; align-items: center;
position: relative; position: relative;
} }
.main-content {
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 40px;
}
.matrix-grid { .matrix-grid {
display: grid; display: grid;
grid-template-columns: repeat(5, 70px); grid-template-columns: repeat(5, 70px);
@ -53,25 +59,28 @@ h1 {
margin-bottom: 20px; margin-bottom: 20px;
text-align: center; text-align: center;
} }
.region-control button { .region-control select {
padding: 10px 15px; padding: 10px 15px;
margin: 5px;
font-size: 14px; font-size: 14px;
cursor: pointer; cursor: pointer;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
background-color: #fff; background-color: #fff;
width: 200px;
} }
/* NEW: Control panel styles for a single column */
.control-panel, .center-lamp-control { .control-panel, .center-lamp-control {
background-color: #444; background-color: #444;
padding: 20px; padding: 20px;
border-radius: 10px; border-radius: 10px;
width: var(--matrix-width); /* NEW: Set width to match the matrix */ width: var(--matrix-width);
margin-bottom: 20px; margin-bottom: 20px;
} }
.control-panel { .control-panel.inactive-control {
display: none; background-color: #333;
filter: saturate(0.2);
}
.control-panel.inactive-control .slider-row {
pointer-events: none;
} }
.control-panel h2, .center-lamp-control h2 { .control-panel h2, .center-lamp-control h2 {
color: #fff; color: #fff;
@ -87,7 +96,7 @@ h1 {
} }
.slider-row { .slider-row {
display: grid; display: grid;
grid-template-columns: 120px 1fr 50px; grid-template-columns: 130px 1fr 50px;
gap: 10px; gap: 10px;
align-items: center; align-items: center;
} }
@ -130,9 +139,13 @@ input.blue::-webkit-slider-runnable-track { background: linear-gradient(to right
white-space: nowrap; white-space: nowrap;
width: 120px; width: 120px;
} }
/* The media query now applies to the control panels directly */ .inactive-control .slider-label {
@media (max-width: 700px) { color: #888;
.control-panel, .center-lamp-control { }
width: var(--matrix-width);
@media (max-width: 1000px) {
.main-content {
flex-direction: column;
align-items: center;
} }
} }

View File

@ -148,8 +148,16 @@
}; };
}); });
$('.region-button').on('click', function() { $('#region-select').on('change', function() {
var region = $(this).data('region'); var region = $(this).val();
// Toggle the inactive state of the control panel based on selection
if (region) {
$('.control-panel').removeClass('inactive-control');
} else {
$('.control-panel').addClass('inactive-control');
}
var newlySelectedLamps = regionMaps[region]; var newlySelectedLamps = regionMaps[region];
// Clear selected class from all lamps // Clear selected class from all lamps
@ -174,14 +182,11 @@
}); });
if (selectedLamps.length > 0) { if (selectedLamps.length > 0) {
$('.control-panel').show();
// Update sliders to reflect the state of the first selected lamp // Update sliders to reflect the state of the first selected lamp
var firstLamp = selectedLamps[0]; var firstLamp = selectedLamps[0];
var firstLampState = lampMatrixState[firstLamp.row][firstLamp.col]; var firstLampState = lampMatrixState[firstLamp.row][firstLamp.col];
updateSliders(firstLampState.ww, firstLampState.cw, firstLampState.blue, ''); updateSliders(firstLampState.ww, firstLampState.cw, firstLampState.blue, '');
} else { }
$('.control-panel').hide();
}
// Send the full matrix state // Send the full matrix state
sendFullMatrixUpdate(lampsToUpdate, true); sendFullMatrixUpdate(lampsToUpdate, true);
@ -220,6 +225,11 @@
sendFullMatrixUpdate([centerLamp]); sendFullMatrixUpdate([centerLamp]);
}); });
// Initial check to set the inactive state
if (!$('#region-select').val()) {
$('.control-panel').addClass('inactive-control');
}
}); });
</script> </script>
</head> </head>
@ -227,61 +237,68 @@
<div class="container"> <div class="container">
<h1>Lamp Matrix Control</h1> <h1>Lamp Matrix Control</h1>
<div class="region-control"> <div class="region-control">
<button class="region-button" data-region="Upper">Upper</button> <label for="region-select">Select Region:</label>
<button class="region-button" data-region="Lower">Lower</button> <select id="region-select">
<button class="region-button" data-region="Left">Left</button> <option value="" disabled selected>-- Select a region --</option>
<button class="region-button" data-region="Right">Right</button> <option value="Upper">Upper</option>
<button class="region-button" data-region="Inner ring">Inner ring</button> <option value="Lower">Lower</option>
<button class="region-button" data-region="Outer ring">Outer ring</button> <option value="Left">Left</option>
<button class="region-button" data-region="All">All</button> <option value="Right">Right</option>
<option value="Inner ring">Inner ring</option>
<option value="Outer ring">Outer ring</option>
<option value="All">All</option>
</select>
</div> </div>
<div class="matrix-grid">
{% for row in range(5) %} <div class="main-content">
{% for col in range(5) %} <div class="matrix-grid">
<div class="lamp" data-row="{{ row }}" data-col="{{ col }}" style="background-color: {{ matrix[row][col] }}; box-shadow: {{ '0 0 15px ' + matrix[row][col] + ', 0 0 25px ' + matrix[row][col] if matrix[row][col] != '#000000' else 'inset 0 0 5px rgba(0,0,0,0.5)' }}"></div> {% for row in range(5) %}
{% for col in range(5) %}
<div class="lamp" data-row="{{ row }}" data-col="{{ col }}" style="background-color: {{ matrix[row][col] }}; box-shadow: {{ '0 0 15px ' + matrix[row][col] + ', 0 0 25px ' + matrix[row][col] if matrix[row][col] != '#000000' else 'inset 0 0 5px rgba(0,0,0,0.5)' }}"></div>
{% endfor %}
{% endfor %} {% endfor %}
{% endfor %} </div>
</div>
<div class="slider-controls">
<div class="slider-controls"> <div class="center-lamp-control">
<div class="center-lamp-control"> <h2>Center Lamp</h2>
<h2>Center Lamp</h2> <div class="slider-group center-slider-group">
<div class="slider-group center-slider-group"> <div class="slider-row">
<div class="slider-row"> <span class="slider-label">Warm White (3000K)</span>
<span class="slider-label">Warm White (3000K)</span> <input type="range" id="center-ww-slider" min="0" max="255" value="0" class="white-3000k">
<input type="range" id="center-ww-slider" min="0" max="255" value="0" class="white-3000k"> <input type="number" id="center-ww-number" min="0" max="255" value="0">
<input type="number" id="center-ww-number" min="0" max="255" value="0"> </div>
</div> <div class="slider-row">
<div class="slider-row"> <span class="slider-label">Cool White (6500K)</span>
<span class="slider-label">Cool White (6500K)</span> <input type="range" id="center-cw-slider" min="0" max="255" value="0" class="white-6500k">
<input type="range" id="center-cw-slider" min="0" max="255" value="0" class="white-6500k"> <input type="number" id="center-cw-number" min="0" max="255" value="0">
<input type="number" id="center-cw-number" min="0" max="255" value="0"> </div>
</div> <div class="slider-row">
<div class="slider-row"> <span class="slider-label">Blue</span>
<span class="slider-label">Blue</span> <input type="range" id="center-blue-slider" min="0" max="255" value="0" class="blue">
<input type="range" id="center-blue-slider" min="0" max="255" value="0" class="blue"> <input type="number" id="center-blue-number" min="0" max="255" value="0">
<input type="number" id="center-blue-number" min="0" max="255" value="0"> </div>
</div> </div>
</div> </div>
</div>
<div class="control-panel"> <div class="control-panel">
<h2>Selected Region</h2> <h2>Selected Region</h2>
<div class="slider-group region-slider-group"> <div class="slider-group region-slider-group">
<div class="slider-row"> <div class="slider-row">
<span class="slider-label">Warm White (3000K)</span> <span class="slider-label">Warm White (3000K)</span>
<input type="range" id="ww-slider" min="0" max="255" value="0" class="white-3000k"> <input type="range" id="ww-slider" min="0" max="255" value="0" class="white-3000k">
<input type="number" id="ww-number" min="0" max="255" value="0"> <input type="number" id="ww-number" min="0" max="255" value="0">
</div> </div>
<div class="slider-row"> <div class="slider-row">
<span class="slider-label">Cool White (6500K)</span> <span class="slider-label">Cool White (6500K)</span>
<input type="range" id="cw-slider" min="0" max="255" value="0" class="white-6500k"> <input type="range" id="cw-slider" min="0" max="255" value="0" class="white-6500k">
<input type="number" id="cw-number" min="0" max="255" value="0"> <input type="number" id="cw-number" min="0" max="255" value="0">
</div> </div>
<div class="slider-row"> <div class="slider-row">
<span class="slider-label">Blue</span> <span class="slider-label">Blue</span>
<input type="range" id="blue-slider" min="0" max="255" value="0" class="blue"> <input type="range" id="blue-slider" min="0" max="255" value="0" class="blue">
<input type="number" id="blue-number" min="0" max="255" value="0"> <input type="number" id="blue-number" min="0" max="255" value="0">
</div>
</div> </div>
</div> </div>
</div> </div>