Modified for correct value sending

This commit is contained in:
Tempest 2025-08-06 17:07:55 +07:00
parent ce0639863c
commit c27e3d661d
2 changed files with 263 additions and 258 deletions

View File

@ -150,13 +150,15 @@ def index():
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():
data = request.get_json()
lamps_to_update = data.get('lamps', [])
r = data.get('r')
g = data.get('g')
b = data.get('b')
r = data.get('ww')
g = data.get('cw')
b = data.get('blue')
if not lamps_to_update:
return jsonify(success=False, message="No lamps selected")

View File

@ -1,271 +1,291 @@
<!DOCTYPE html>
<html>
<head>
<title>RGB Lamp Matrix Control</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>Lamp Matrix Control</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.matrix-grid {
display: grid;
grid-template-columns: repeat(5, 70px);
grid-template-rows: repeat(5, 70px);
gap: 20px;
padding: 20px;
background-color: #333;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
margin-bottom: 20px;
}
.lamp {
width: 70px;
height: 70px;
border-radius: 10%;
background-color: #000;
transition: box-shadow 0.2s, transform 0.1s;
cursor: pointer;
border: 2px solid transparent;
}
.lamp.on {
box-shadow: 0 0 15px currentColor, 0 0 25px currentColor;
}
.lamp.selected {
border: 2px solid #fff;
transform: scale(1.1);
}
h1 {
color: #333;
margin-bottom: 20px;
}
.region-control {
margin-bottom: 20px;
text-align: center;
}
.region-control button {
padding: 10px 15px;
margin: 5px;
font-size: 14px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #fff;
}
.slider-controls {
display: flex;
gap: 20px;
align-items: flex-start;
}
.control-panel {
background-color: #444;
padding: 20px;
border-radius: 10px;
display: none;
}
.slider-group {
width: 250px;
display: flex;
flex-direction: column;
gap: 5px;
}
.slider-group input {
width: 100%;
-webkit-appearance: none;
height: 8px;
border-radius: 5px;
outline: none;
cursor: pointer;
}
.slider-group input::-webkit-slider-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
background: #fff;
cursor: pointer;
box-shadow: 0 0 5px rgba(0,0,0,0.5);
margin-top: 2px;
}
.slider-group input::-webkit-slider-runnable-track {
height: 24px;
border-radius: 12px;
background: #aaa; /* Generic solid color */
}
.slider-label {
color: #fff;
font-size: 14px;
text-align: left;
}
.center-lamp-control {
margin-top: 10px;
background-color: #444;
padding: 20px;
border-radius: 10px;
}
.center-lamp-control h2 {
color: #fff;
font-size: 16px;
margin-bottom: 10px;
}
</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// === Client-Side State and Helper Functions ===
/* var clientMatrix = [
[{% for col in range(5) %}'{{ matrix[0][col] }}'{% if not loop.last %}, {% endif %}{% endfor %}],
[{% for col in range(5) %}'{{ matrix[1][col] }}'{% if not loop.last %}, {% endif %}{% endfor %}],
[{% for col in range(5) %}'{{ matrix[2][col] }}'{% if not loop.last %}, {% endif %}{% endfor %}],
[{% for col in range(5) %}'{{ matrix[3][col] }}'{% if not loop.last %}, {% endif %}{% endfor %}],
[{% for col in range(5) %}'{{ matrix[4][col] }}'{% if not loop.last %}, {% endif %}{% endfor %}]
];*/
var clientMatrix = [
{% for row in matrix %}
[{% for color in row %}'{{ color }}'{% if not loop.last %}, {% endif %}{% endfor %}]{% if not loop.last %}, {% endif %}
{% endfor %}
];
var selectedLamps = [];
const matrixSize = 5;
const centerCoords = {row: Math.floor(matrixSize / 2), col: Math.floor(matrixSize / 2)};
const white3000k = {r: 255, g: 180, b: 100};
const white6500k = {r: 200, g: 220, b: 255};
const blue = {r: 0, g: 0, b: 255};
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : {r: 0, g: 0, b: 0};
// NEW: Function to update sliders based on the three light values
function updateSliders(ww, cw, blue) {
$('#ww-slider').val(ww);
$('#cw-slider').val(cw);
$('#blue-slider').val(blue);
}
function getMixedColor(w3k, w6k, b) {
let final_r = Math.min(255, Math.round((w3k / 255 * white3000k.r) + (w6k / 255 * white6500k.r)));
let final_g = Math.min(255, Math.round((w3k / 255 * white3000k.g) + (w6k / 255 * white6500k.g)));
let final_b = Math.min(255, Math.round((w3k / 255 * white3000k.b) + (w6k / 255 * white6500k.b) + (b / 255 * blue.b)));
let hex = '#' + ('0' + final_r.toString(16)).slice(-2) + ('0' + final_g.toString(16)).slice(-2) + ('0' + final_b.toString(16)).slice(-2);
return {r: final_r, g: final_g, b: final_b, hex: hex};
// NEW: Function to calculate a visual RGB color from the three light values
function calculateRgb(ww, cw, blue) {
// A simple approximation for UI display
var r = Math.min(255, ww + cw);
var g = Math.min(255, ww + cw + blue);
var b = Math.min(255, blue + cw);
return '#' + ('0' + r.toString(16)).slice(-2) + ('0' + g.toString(16)).slice(-2) + ('0' + b.toString(16)).slice(-2);
}
// CORRECTED: Dynamic Region Mapping Functions
function getUpperRegion(n) {
let region = [];
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
// Correctly includes all lamps in the upper half of the grid
if (r < centerCoords.row) {
region.push({row: r, col: c});
}
}
}
return region;
}
function getLowerRegion(n) {
let region = [];
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
// Correctly includes all lamps in the lower half of the grid
if (r > centerCoords.row) {
region.push({row: r, col: c});
}
}
}
return region;
}
function getLeftRegion(n) {
let region = [];
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
// Correctly includes all lamps in the left half of the grid
if (c < centerCoords.col) {
region.push({row: r, col: c});
}
}
}
return region;
}
function getRightRegion(n) {
let region = [];
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
// Correctly includes all lamps in the right half of the grid
if (c > centerCoords.col) {
region.push({row: r, col: c});
}
}
}
return region;
}
function getInnerRing(n) {
let region = [];
let start = centerCoords.row - 1;
let end = centerCoords.row + 1;
for (let r = start; r <= end; r++) {
for (let c = start; c <= end; c++) {
if (r !== centerCoords.row || c !== centerCoords.col) {
region.push({row: r, col: c});
}
}
}
return region;
}
function getOuterRing(n) {
let region = [];
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
if (r === 0 || r === n - 1 || c === 0 || c === n - 1) {
region.push({row: r, col: c});
}
}
}
return region;
}
function renderMatrix() {
for (let r = 0; r < 5; r++) {
for (let c = 0; c < 5; c++) {
let lampElement = $(`.lamp[data-row="${r}"][data-col="${c}"]`);
let color = clientMatrix[r][c];
let isSelected = selectedLamps.some(lamp => lamp.row === r && lamp.col === c);
lampElement.css('background-color', color);
if (isSelected) {
lampElement.addClass('selected');
} else {
lampElement.removeClass('selected');
}
if (color !== '#000000') {
lampElement.addClass('on');
lampElement.css('box-shadow', `0 0 15px ${color}, 0 0 25px ${color}`);
} else {
lampElement.removeClass('on');
lampElement.css('box-shadow', 'inset 0 0 5px rgba(0,0,0,0.5)');
}
}
}
}
function updateSlidersFromColor(targetColor) {
let rgb = hexToRgb(targetColor);
$('#white-3000k-slider, #white-6500k-slider, #blue-slider').val(0);
$('#white-3000k-value, #white-6500k-value, #blue-value').val(0);
}
// === Event Handlers ===
$(document).ready(function() {
renderMatrix();
var regionMaps = {
'Upper': getUpperRegion(matrixSize),
'Lower': getLowerRegion(matrixSize),
'Left': getLeftRegion(matrixSize),
'Right': getRightRegion(matrixSize),
'Inner ring': getInnerRing(matrixSize),
'Outer ring': getOuterRing(matrixSize)
'Upper': [
{row: 0, col: 0}, {row: 0, col: 1}, {row: 0, col: 2}, {row: 0, col: 3}, {row: 0, col: 4},
{row: 1, col: 0}, {row: 1, col: 1}, {row: 1, col: 2}, {row: 1, col: 3}, {row: 1, col: 4},
],
'Lower': [
{row: 3, col: 0}, {row: 3, col: 1}, {row: 3, col: 2}, {row: 3, col: 3}, {row: 3, col: 4},
{row: 4, col: 0}, {row: 4, col: 1}, {row: 4, col: 2}, {row: 4, col: 3}, {row: 4, col: 4},
],
'Left': [
{row: 0, col: 0}, {row: 1, col: 0}, {row: 2, col: 0}, {row: 3, col: 0}, {row: 4, col: 0},
{row: 0, col: 1}, {row: 1, col: 1}, {row: 2, col: 1}, {row: 3, col: 1}, {row: 4, col: 1},
],
'Right': [
{row: 0, col: 3}, {row: 1, col: 3}, {row: 2, col: 3}, {row: 3, col: 3}, {row: 4, col: 3},
{row: 0, col: 4}, {row: 1, col: 4}, {row: 2, col: 4}, {row: 3, col: 4}, {row: 4, col: 4},
],
'Inner ring': [
{row: 1, col: 1}, {row: 1, col: 2}, {row: 1, col: 3},
{row: 2, col: 1}, {row: 2, col: 3},
{row: 3, col: 1}, {row: 3, col: 2}, {row: 3, col: 3}
],
'Outer ring': [
{row: 0, col: 0}, {row: 0, col: 1}, {row: 0, col: 2}, {row: 0, col: 3}, {row: 0, col: 4},
{row: 1, col: 0}, {row: 1, col: 4},
{row: 2, col: 0}, {row: 2, col: 4},
{row: 3, col: 0}, {row: 3, col: 4},
{row: 4, col: 0}, {row: 4, col: 1}, {row: 4, col: 2}, {row: 4, col: 3}, {row: 4, col: 4},
]
};
$('.region-button').on('click', function() {
var region = $(this).data('region');
selectedLamps = regionMaps[region];
$('.lamp').removeClass('selected');
$('.lamp').not('[data-row="2"][data-col="2"]').css('box-shadow', 'inset 0 0 5px rgba(0,0,0,0.5)');
selectedLamps.forEach(function(lamp) {
$(`.lamp[data-row="${lamp.row}"][data-col="${lamp.col}"]`).addClass('selected');
});
if (selectedLamps.length > 0) {
$('.control-panel').show();
$('.region-slider-group input').prop('disabled', false);
updateSlidersFromColor(clientMatrix[selectedLamps[0].row][selectedLamps[0].col]);
// NEW: Update sliders based on first lamp's current state
var firstLamp = selectedLamps[0];
var firstLampElement = $(`.lamp[data-row="${firstLamp.row}"][data-col="${firstLamp.col}"]`);
// Note: This requires the Python backend to send back the ww, cw, blue values
// in the initial render, which is a required change from previous versions.
// For now, sliders will default to 0.
updateSliders(0, 0, 0);
} else {
$('.control-panel').hide();
$('.region-slider-group input').prop('disabled', true);
}
renderMatrix();
});
$('.region-slider-group input[type="range"]').on('input', function() {
// NEW: Event listener for the region sliders
$('.region-slider-group input').on('input', function() {
if (selectedLamps.length === 0) return;
var w3k = $('#white-3000k-slider').val();
var w6k = $('#white-6500k-slider').val();
var b = $('#blue-slider').val();
$('#white-3000k-value').val(w3k);
$('#white-6500k-value').val(w6k);
$('#blue-value').val(b);
var finalColor = getMixedColor(w3k, w6k, b);
let centerColor = clientMatrix[centerCoords.row][centerCoords.col];
for (let r = 0; r < 5; r++) {
for (let c = 0; c < 5; c++) {
if (r === centerCoords.row && c === centerCoords.col) continue;
clientMatrix[r][c] = '#000000';
}
}
selectedLamps.forEach(lamp => {
clientMatrix[lamp.row][lamp.col] = finalColor.hex;
});
var ww = $('#ww-slider').val();
var cw = $('#cw-slider').val();
var blue = $('#blue-slider').val();
var data = {
lamps: selectedLamps,
r: finalColor.r,
g: finalColor.g,
b: finalColor.b
ww: ww,
cw: cw,
blue: blue
};
$.ajax({ url: '/set_color', type: 'POST', contentType: 'application/json', data: JSON.stringify(data) });
renderMatrix();
$.ajax({
url: '/set_color',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
if (response.success) {
var newColor = calculateRgb(ww, cw, blue);
$('.lamp').each(function() {
var currentLamp = $(this);
var lampRow = currentLamp.data('row');
var lampCol = currentLamp.data('col');
var isCenterLamp = (lampRow === 2 && lampCol === 2);
var isSelected = selectedLamps.some(lamp => lamp.row === lampRow && lamp.col === lampCol);
if (isSelected) {
currentLamp.css('background-color', newColor);
if (newColor === '#000000') {
currentLamp.removeClass('on');
} else {
currentLamp.addClass('on');
currentLamp.css('box-shadow', `0 0 15px ${newColor}, 0 0 25px ${newColor}`);
}
} else if (!isCenterLamp) {
currentLamp.css('background-color', '#000000');
currentLamp.removeClass('on');
}
});
}
}
});
});
$('.region-slider-group input[type="number"]').on('input', function() {
var value = parseInt($(this).val());
if (isNaN(value) || value < 0) value = 0;
if (value > 255) value = 255;
$(this).val(value);
$(this).siblings('input[type="range"]').val(value).trigger('input');
});
$('.center-slider-group input[type="range"]').on('input', function() {
var w3k = $('#center-white-3000k-slider').val();
var w6k = $('#center-white-6500k-slider').val();
var b = $('#center-blue-slider').val();
$('#center-white-3000k-value').val(w3k);
$('#center-white-6500k-value').val(w6k);
$('#center-blue-value').val(b);
var finalColor = getMixedColor(w3k, w6k, b);
clientMatrix[centerCoords.row][centerCoords.col] = finalColor.hex;
// NEW: Event listener for the center lamp sliders
$('.center-slider-group input').on('input', function() {
var ww = $('#center-ww-slider').val();
var cw = $('#center-cw-slider').val();
var blue = $('#center-blue-slider').val();
var data = {
lamps: [{row: 2, col: 2}],
r: finalColor.r,
g: finalColor.g,
b: finalColor.b
ww: ww,
cw: cw,
blue: blue
};
$.ajax({ url: '/set_color', type: 'POST', contentType: 'application/json', data: JSON.stringify(data) });
renderMatrix();
});
$.ajax({
url: '/set_color',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function(response) {
if (response.success) {
var newColor = calculateRgb(ww, cw, blue);
var centerLamp = $(`.lamp[data-row="2"][data-col="2"]`);
centerLamp.css('background-color', newColor);
$('.center-slider-group input[type="number"]').on('input', function() {
var value = parseInt($(this).val());
if (isNaN(value) || value < 0) value = 0;
if (value > 255) value = 255;
$(this).val(value);
$(this).siblings('input[type="range"]').val(value).trigger('input');
if (newColor === '#000000') {
centerLamp.removeClass('on');
} else {
centerLamp.addClass('on');
centerLamp.css('box-shadow', `0 0 15px ${newColor}, 0 0 25px ${newColor}`);
}
}
}
});
});
});
</script>
</head>
<body>
<div class="container">
<h1>RGB Lamp Matrix Control</h1>
<h1>Lamp Matrix Control</h1>
<div class="region-control">
<button class="region-button" data-region="Upper">Upper</button>
<button class="region-button" data-region="Lower">Lower</button>
@ -282,44 +302,27 @@
{% endfor %}
</div>
<div class="center-lamp-control">
<h2>Center Lamp</h2>
<div class="slider-group center-slider-group">
<div class="slider-row">
<span class="slider-label">White 3000K</span>
<input type="range" id="center-white-3000k-slider" class="white-3000k" min="0" max="255" value="0">
<input type="number" id="center-white-3000k-value" min="0" max="255" value="0">
</div>
<div class="slider-row">
<span class="slider-label">White 6500K</span>
<input type="range" id="center-white-6500k-slider" class="white-6500k" min="0" max="255" value="0">
<input type="number" id="center-white-6500k-value" min="0" max="255" value="0">
</div>
<div class="slider-row">
<div class="slider-controls">
<div class="center-lamp-control">
<h2>Center Lamp</h2>
<div class="slider-group center-slider-group">
<span class="slider-label">Warm White (3000K)</span>
<input type="range" id="center-ww-slider" min="0" max="255" value="0">
<span class="slider-label">Cool White (6500K)</span>
<input type="range" id="center-cw-slider" min="0" max="255" value="0">
<span class="slider-label">Blue</span>
<input type="range" id="center-blue-slider" class="blue" min="0" max="255" value="0">
<input type="number" id="center-blue-value" min="0" max="255" value="0">
<input type="range" id="center-blue-slider" min="0" max="255" value="0">
</div>
</div>
</div>
<div class="control-panel">
<h2>Region</h2>
<div class="slider-group region-slider-group">
<div class="slider-row">
<span class="slider-label">White 3000K</span>
<input type="range" id="white-3000k-slider" class="white-3000k" min="0" max="255" value="0" disabled>
<input type="number" id="white-3000k-value" min="0" max="255" value="0" disabled>
</div>
<div class="slider-row">
<span class="slider-label">White 6500K</span>
<input type="range" id="white-6500k-slider" class="white-6500k" min="0" max="255" value="0" disabled>
<input type="number" id="white-6500k-value" min="0" max="255" value="0" disabled>
</div>
<div class="slider-row">
<div class="control-panel">
<div class="slider-group region-slider-group">
<span class="slider-label">Warm White (3000K)</span>
<input type="range" id="ww-slider" min="0" max="255" value="0">
<span class="slider-label">Cool White (6500K)</span>
<input type="range" id="cw-slider" min="0" max="255" value="0">
<span class="slider-label">Blue</span>
<input type="range" id="blue-slider" class="blue" min="0" max="255" value="0" disabled>
<input type="number" id="blue-value" min="0" max="255" value="0" disabled>
<input type="range" id="blue-slider" min="0" max="255" value="0">
</div>
</div>
</div>