remove web app code, add note in comment about where to find it
This commit is contained in:
parent
57d39d0fb3
commit
b576e77a20
6 changed files with 1 additions and 504 deletions
|
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
* This sketch works with the web interface in the /webserial directory,
|
||||
* which can be accessed at: https://adafruit.github.io/Adafruit_OPT4048/webserial/
|
||||
* Code for web app is in gh-pages branch: https://github.com/adafruit/Adafruit_OPT4048/tree/gh-pages
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
# OPT4048 CIE Color Plotter
|
||||
|
||||
This web interface allows you to visualize color measurements from an Adafruit OPT4048 color sensor in real-time using the Web Serial API.
|
||||
|
||||
## How to Use
|
||||
|
||||
1. **Upload the Arduino sketch**: First, upload the `opt4048_webserial.ino` sketch from the examples folder to your Arduino board.
|
||||
|
||||
2. **Connect to this web page**: You can access it at:
|
||||
- https://adafruit.github.io/Adafruit_OPT4048/webserial/
|
||||
- Or host the page locally for development
|
||||
|
||||
3. **Connect to your Arduino**: Click the "Connect to Arduino" button and select your Arduino from the popup menu.
|
||||
|
||||
4. **View measurements**: The sensor readings will appear on the CIE chromaticity diagram, showing you exactly where the measured color falls in the CIE color space.
|
||||
|
||||
## Features
|
||||
|
||||
- Displays CIE x,y coordinates in real-time
|
||||
- Plots the color point on a standard CIE 1931 chromaticity diagram
|
||||
- Shows lux (brightness) and color temperature (CCT) values
|
||||
- Provides approximate RGB color visualization
|
||||
- Monitors serial output for debugging
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
This interface uses the Web Serial API, which is currently supported in:
|
||||
- Google Chrome (version 89+)
|
||||
- Microsoft Edge (version 89+)
|
||||
- Opera (version 75+)
|
||||
|
||||
It is **not** supported in Firefox or Safari due to their Web Serial API implementation status.
|
||||
|
||||
## About the OPT4048 Sensor
|
||||
|
||||
The OPT4048 is a high-precision tristimulus XYZ color sensor by Texas Instruments. The Adafruit breakout board makes it easy to interface with this sensor using I2C.
|
||||
|
||||
This sensor provides accurate color measurements in XYZ color space, which can be converted to standard CIE 1931 xy chromaticity coordinates.
|
||||
|
||||
## File Structure
|
||||
|
||||
- `index.html` - The main webpage
|
||||
- `script.js` - JavaScript code for communication and visualization
|
||||
- `cie1931_diagram.svg` - SVG image of the CIE 1931 chromaticity diagram
|
||||
|
||||
## License
|
||||
|
||||
MIT license, all text here must be included in any redistribution
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 6.6 KiB |
|
|
@ -1,158 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OPT4048 CIE Color Plotter</title>
|
||||
<!-- oEmbed Discovery Links -->
|
||||
<link rel="alternate" type="application/json+oembed" href="https://adafruit.github.io/Adafruit_OPT4048/webserial/oembed.json" title="Adafruit OPT4048 Demo" />
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
}
|
||||
.controls {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
.visualization {
|
||||
flex: 2;
|
||||
min-width: 500px;
|
||||
}
|
||||
#cie-diagram {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#cie-diagram img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
#data-point {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: red;
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||
z-index: 10;
|
||||
}
|
||||
#color-sample {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #ccc;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#serial-log {
|
||||
height: 200px;
|
||||
overflow-y: auto;
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
}
|
||||
button {
|
||||
padding: 10px 16px;
|
||||
margin: 5px 0;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
button:disabled {
|
||||
background-color: #cccccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.data-display {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.data-box {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
padding: 15px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
.data-box h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
.data-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>OPT4048 CIE Color Plotter</h1>
|
||||
<p>Connect your Arduino with OPT4048 sensor to visualize color measurements on a CIE diagram.</p>
|
||||
|
||||
<div class="container">
|
||||
<div class="controls">
|
||||
<button id="connect-button">Connect to Arduino</button>
|
||||
<button id="disconnect-button" disabled>Disconnect</button>
|
||||
<button id="clear-button">Clear Log</button>
|
||||
|
||||
<h2>Connection Status</h2>
|
||||
<p id="status">Not connected</p>
|
||||
|
||||
<h2>Serial Monitor</h2>
|
||||
<div id="serial-log"></div>
|
||||
</div>
|
||||
|
||||
<div class="visualization">
|
||||
<h2>CIE 1931 Chromaticity Diagram</h2>
|
||||
<div id="cie-diagram">
|
||||
<img src="cie1931_diagram.svg" alt="CIE 1931 Chromaticity Diagram">
|
||||
<div id="data-point" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
<div class="data-display">
|
||||
<div class="data-box">
|
||||
<h3>CIE x</h3>
|
||||
<div id="cie-x" class="data-value">-</div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<h3>CIE y</h3>
|
||||
<div id="cie-y" class="data-value">-</div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<h3>Lux</h3>
|
||||
<div id="lux" class="data-value">-</div>
|
||||
</div>
|
||||
<div class="data-box">
|
||||
<h3>CCT (K)</h3>
|
||||
<div id="cct" class="data-value">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-box">
|
||||
<h3>Color Approximation</h3>
|
||||
<div id="color-sample"></div>
|
||||
<small>(Note: This is a rough approximation)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"type": "rich",
|
||||
"title": "Adafruit OPT4048 Library",
|
||||
"provider_name": "Adafruit",
|
||||
"provider_url": "https://www.adafruit.com",
|
||||
"author_name": "Adafruit",
|
||||
"author_url": "https://github.com/adafruit",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"html": "<iframe src='https://adafruit.github.io/Adafruit_OPT4048/webserial/' width='800' height='600' style='border: 1px solid #ddd; border-radius: 4px; max-width: 100%;' allow='serial; usb' loading='lazy' title='Adafruit OPT4048 Arduino Library'></iframe>"
|
||||
}
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
// Global variables
|
||||
let port;
|
||||
let reader;
|
||||
let writer;
|
||||
let readTimeout;
|
||||
let keepReading = false;
|
||||
let decoder = new TextDecoder();
|
||||
let lineBuffer = '';
|
||||
|
||||
// DOM Elements
|
||||
const connectButton = document.getElementById('connect-button');
|
||||
const disconnectButton = document.getElementById('disconnect-button');
|
||||
const clearButton = document.getElementById('clear-button');
|
||||
const statusDisplay = document.getElementById('status');
|
||||
const serialLog = document.getElementById('serial-log');
|
||||
const dataPoint = document.getElementById('data-point');
|
||||
const cieXDisplay = document.getElementById('cie-x');
|
||||
const cieYDisplay = document.getElementById('cie-y');
|
||||
const luxDisplay = document.getElementById('lux');
|
||||
const cctDisplay = document.getElementById('cct');
|
||||
const colorSample = document.getElementById('color-sample');
|
||||
|
||||
// Check if Web Serial API is supported
|
||||
if ('serial' in navigator) {
|
||||
connectButton.addEventListener('click', connectToArduino);
|
||||
disconnectButton.addEventListener('click', disconnectFromArduino);
|
||||
clearButton.addEventListener('click', clearLog);
|
||||
} else {
|
||||
statusDisplay.textContent = 'Web Serial API not supported in this browser. Try Chrome or Edge.';
|
||||
connectButton.disabled = true;
|
||||
}
|
||||
|
||||
// Connect to Arduino via Web Serial
|
||||
async function connectToArduino() {
|
||||
try {
|
||||
// Request a port and open a connection
|
||||
port = await navigator.serial.requestPort();
|
||||
await port.open({ baudRate: 115200 });
|
||||
|
||||
// Set up the reader and writer
|
||||
reader = port.readable.getReader();
|
||||
writer = port.writable.getWriter();
|
||||
|
||||
// Enable/disable buttons
|
||||
connectButton.disabled = true;
|
||||
disconnectButton.disabled = false;
|
||||
statusDisplay.textContent = 'Connected to Arduino';
|
||||
addToLog('Connected to Arduino', 'status');
|
||||
|
||||
// Start reading data
|
||||
keepReading = true;
|
||||
readSerialData();
|
||||
} catch (error) {
|
||||
console.error('Error connecting to Arduino:', error);
|
||||
addToLog(`Error connecting: ${error.message}`, 'error');
|
||||
statusDisplay.textContent = 'Connection failed';
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect from Arduino
|
||||
async function disconnectFromArduino() {
|
||||
if (reader) {
|
||||
keepReading = false;
|
||||
clearTimeout(readTimeout);
|
||||
|
||||
try {
|
||||
await reader.cancel();
|
||||
await reader.releaseLock();
|
||||
reader = null;
|
||||
} catch (error) {
|
||||
console.error('Error releasing reader:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (writer) {
|
||||
try {
|
||||
await writer.close();
|
||||
writer = null;
|
||||
} catch (error) {
|
||||
console.error('Error releasing writer:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (port) {
|
||||
try {
|
||||
await port.close();
|
||||
port = null;
|
||||
} catch (error) {
|
||||
console.error('Error closing port:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Update UI
|
||||
connectButton.disabled = false;
|
||||
disconnectButton.disabled = true;
|
||||
statusDisplay.textContent = 'Disconnected';
|
||||
addToLog('Disconnected from Arduino', 'status');
|
||||
hideDataPoint();
|
||||
}
|
||||
|
||||
// Read data from the serial port
|
||||
async function readSerialData() {
|
||||
while (port && keepReading) {
|
||||
try {
|
||||
const { value, done } = await reader.read();
|
||||
|
||||
if (done) {
|
||||
// Reader has been canceled
|
||||
break;
|
||||
}
|
||||
|
||||
// Process the received data
|
||||
processSerialData(decoder.decode(value));
|
||||
} catch (error) {
|
||||
console.error('Error reading data:', error);
|
||||
addToLog(`Error reading data: ${error.message}`, 'error');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we exited the loop without being explicitly disconnected
|
||||
if (keepReading) {
|
||||
disconnectFromArduino();
|
||||
}
|
||||
}
|
||||
|
||||
// Process data received from Arduino
|
||||
function processSerialData(data) {
|
||||
// Add received data to the buffer
|
||||
lineBuffer += data;
|
||||
|
||||
// Process complete lines
|
||||
let lineEnd;
|
||||
while ((lineEnd = lineBuffer.indexOf('\n')) !== -1) {
|
||||
const line = lineBuffer.substring(0, lineEnd).trim();
|
||||
lineBuffer = lineBuffer.substring(lineEnd + 1);
|
||||
|
||||
if (line) {
|
||||
addToLog(line);
|
||||
parseDataFromLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse data from a line received from Arduino
|
||||
function parseDataFromLine(line) {
|
||||
// Look for CIE x value
|
||||
const cieXMatch = line.match(/CIE x: ([\d.]+)/);
|
||||
if (cieXMatch) {
|
||||
const cieX = parseFloat(cieXMatch[1]);
|
||||
cieXDisplay.textContent = cieX.toFixed(6);
|
||||
}
|
||||
|
||||
// Look for CIE y value
|
||||
const cieYMatch = line.match(/CIE y: ([\d.]+)/);
|
||||
if (cieYMatch) {
|
||||
const cieY = parseFloat(cieYMatch[1]);
|
||||
cieYDisplay.textContent = cieY.toFixed(6);
|
||||
|
||||
// If we have both x and y, update the plot
|
||||
if (cieXMatch) {
|
||||
const cieX = parseFloat(cieXMatch[1]);
|
||||
updateCIEPlot(cieX, cieY);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for Lux value
|
||||
const luxMatch = line.match(/Lux: ([\d.]+)/);
|
||||
if (luxMatch) {
|
||||
const lux = parseFloat(luxMatch[1]);
|
||||
luxDisplay.textContent = lux.toFixed(2);
|
||||
}
|
||||
|
||||
// Look for Color Temperature value
|
||||
const cctMatch = line.match(/Color Temperature: ([\d.]+)/);
|
||||
if (cctMatch) {
|
||||
const cct = parseFloat(cctMatch[1]);
|
||||
cctDisplay.textContent = cct.toFixed(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the CIE plot with new data point
|
||||
function updateCIEPlot(x, y) {
|
||||
// Get the dimensions of the CIE diagram image
|
||||
const cieImage = document.querySelector('#cie-diagram img');
|
||||
const imageRect = cieImage.getBoundingClientRect();
|
||||
|
||||
// The SVG has a coordinate system where:
|
||||
// - X axis is marked from 0.0 to 0.8 (matched to pixel positions 60 to 470)
|
||||
// - Y axis is marked from 0.0 to 0.9 (matched to pixel positions 476 to 15)
|
||||
|
||||
// Define the SVG's coordinate mapping
|
||||
const svgXMin = 60, svgXMax = 470; // Left and right edge pixel positions in SVG
|
||||
const svgYMin = 476, svgYMax = 15; // Bottom and top edge pixel positions in SVG
|
||||
const cieXMin = 0.0, cieXMax = 0.8; // Min and max x chromaticity values
|
||||
const cieYMin = 0.0, cieYMax = 0.9; // Min and max y chromaticity values
|
||||
|
||||
// Map the CIE coordinates to percentages within the SVG viewport
|
||||
const svgWidth = svgXMax - svgXMin;
|
||||
const svgHeight = svgYMin - svgYMax;
|
||||
|
||||
// Calculate the percentage position (normalize to SVG viewBox)
|
||||
const xPercent = ((x - cieXMin) / (cieXMax - cieXMin)) * 100;
|
||||
const yPercent = (1 - ((y - cieYMin) / (cieYMax - cieYMin))) * 100; // Invert y-axis
|
||||
|
||||
// Set the data point position
|
||||
dataPoint.style.left = `${xPercent}%`;
|
||||
dataPoint.style.top = `${yPercent}%`;
|
||||
dataPoint.style.display = 'block';
|
||||
|
||||
// Update the color sample with an approximate RGB color
|
||||
updateColorSample(x, y);
|
||||
}
|
||||
|
||||
// Convert CIE XYZ to RGB for color approximation
|
||||
function updateColorSample(x, y) {
|
||||
// Calculate XYZ from xyY (assuming Y=1 for relative luminance)
|
||||
const Y = 1.0;
|
||||
const X = (x * Y) / y;
|
||||
const Z = ((1 - x - y) * Y) / y;
|
||||
|
||||
// XYZ to RGB conversion (sRGB)
|
||||
// Using the standard D65 transformation matrix
|
||||
let r = X * 3.2406 - Y * 1.5372 - Z * 0.4986;
|
||||
let g = -X * 0.9689 + Y * 1.8758 + Z * 0.0415;
|
||||
let b = X * 0.0557 - Y * 0.2040 + Z * 1.0570;
|
||||
|
||||
// Apply gamma correction
|
||||
r = r <= 0.0031308 ? 12.92 * r : 1.055 * Math.pow(r, 1/2.4) - 0.055;
|
||||
g = g <= 0.0031308 ? 12.92 * g : 1.055 * Math.pow(g, 1/2.4) - 0.055;
|
||||
b = b <= 0.0031308 ? 12.92 * b : 1.055 * Math.pow(b, 1/2.4) - 0.055;
|
||||
|
||||
// Clamp RGB values between 0 and 1
|
||||
r = Math.min(Math.max(0, r), 1);
|
||||
g = Math.min(Math.max(0, g), 1);
|
||||
b = Math.min(Math.max(0, b), 1);
|
||||
|
||||
// Convert to 8-bit color values
|
||||
const ri = Math.round(r * 255);
|
||||
const gi = Math.round(g * 255);
|
||||
const bi = Math.round(b * 255);
|
||||
|
||||
// Set the background color of the sample
|
||||
colorSample.style.backgroundColor = `rgb(${ri}, ${gi}, ${bi})`;
|
||||
}
|
||||
|
||||
// Hide the data point and reset all displays
|
||||
function hideDataPoint() {
|
||||
dataPoint.style.display = 'none';
|
||||
cieXDisplay.textContent = '-';
|
||||
cieYDisplay.textContent = '-';
|
||||
luxDisplay.textContent = '-';
|
||||
cctDisplay.textContent = '-';
|
||||
colorSample.style.backgroundColor = 'transparent';
|
||||
}
|
||||
|
||||
// Add a message to the serial log
|
||||
function addToLog(message, type = 'data') {
|
||||
const entry = document.createElement('div');
|
||||
entry.textContent = message;
|
||||
entry.className = `log-entry ${type}`;
|
||||
serialLog.appendChild(entry);
|
||||
serialLog.scrollTop = serialLog.scrollHeight;
|
||||
}
|
||||
|
||||
// Clear the serial log
|
||||
function clearLog() {
|
||||
serialLog.innerHTML = '';
|
||||
}
|
||||
|
||||
// Send a command to the Arduino
|
||||
async function sendCommand(command) {
|
||||
if (writer) {
|
||||
try {
|
||||
const encoder = new TextEncoder();
|
||||
await writer.write(encoder.encode(command + '\n'));
|
||||
addToLog(`Sent: ${command}`, 'command');
|
||||
} catch (error) {
|
||||
console.error('Error sending command:', error);
|
||||
addToLog(`Error sending command: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue