Skip to content

websocket server example #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions LICENSES/LicenseRef-Wikipedia-Public-Domain.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I, the copyright holder of this work, release this work into the public domain. This applies worldwide.
In some countries this may not be legally possible; if so:
I grant anyone the right to use this work for any purpose, without any conditions, unless such conditions are required by law.
3 changes: 0 additions & 3 deletions adafruit_opt4048.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@ def __init__(self, i2c_bus, address=_OPT4048_DEFAULT_ADDR):
def init(self):
"""Initialize the sensor and verify the device ID"""
# Check device ID
print(f"id: {hex(self._device_id)}")
if self._device_id != _OPT4048_CHIP_ID:
raise RuntimeError("Failed to find an OPT4048 sensor - check your wiring!")

Expand Down Expand Up @@ -593,7 +592,6 @@ def threshold_low(self):
# Read the exponent and mantissa from the threshold low register
exponent = self._threshold_low_exponent
mantissa = self._threshold_low_mantissa
print(f"exponent: {exponent} mantissa: {mantissa}")
# Calculate ADC code value by applying the exponent as a bit shift
# ADD 8 to the exponent as per datasheet equations 12-13
return mantissa << (8 + exponent)
Expand Down Expand Up @@ -697,7 +695,6 @@ def all_channels(self):

# Combine MSB and LSB to form the 20-bit mantissa
mant = (msb << 8) | lsb
# print(f"ch: {ch} exp: {exp} msb: {msb} lsb: {lsb} counter: {counter} crc: {crc} mant: {mant}") # noqa: E501
# Calculate CRC
# Initialize CRC variables
x0 = 0 # CRC bit 0
Expand Down
79 changes: 79 additions & 0 deletions examples/opt4048_websocket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim C for Adafruit Industries
# SPDX-License-Identifier: MIT

from asyncio import create_task, gather, run
from asyncio import sleep as async_sleep

import board
import socketpool
import wifi
from adafruit_httpserver import GET, FileResponse, Request, Response, Server, Websocket

from adafruit_opt4048 import OPT4048, ConversionTime, Mode, Range

pool = socketpool.SocketPool(wifi.radio)
server = Server(pool, debug=True, root_path="opt4048_ws_static")

websocket: Websocket = None

READ_INTERVAL = 0.1 # seconds

i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
sensor = OPT4048(i2c)

sensor.range = Range.AUTO
sensor.conversion_time = ConversionTime.TIME_100MS
sensor.mode = Mode.CONTINUOUS


@server.route("/connect-websocket", GET)
def connect_client(request: Request):
global websocket # noqa: PLW0603, global use

if websocket is not None:
websocket.close() # Close any existing connection

websocket = Websocket(request)

return websocket


server.start(str(wifi.radio.ipv4_address))


async def handle_http_requests():
while True:
server.poll()

await async_sleep(0)


async def send_color_data_ws():
while True:
if websocket is not None:
try:
x, y, lux = sensor.cie
out_msg = "---CIE Data---\n"
out_msg += f"CIE x: {x}\n"
out_msg += f"CIE y: {y}\n"
out_msg += f"Lux: {lux}\n"
out_msg += f"Color Temperature: {sensor.calculate_color_temperature(x, y)} K\n"
out_msg += "-------------\n"

websocket.send_message(out_msg, fail_silently=True)
except RuntimeError:
# error reading sensor
pass

await async_sleep(READ_INTERVAL)


async def main():
await gather(
create_task(handle_http_requests()),
create_task(send_color_data_ws()),
)


run(main())
3 changes: 3 additions & 0 deletions examples/opt4048_ws_static/cie1931_diagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions examples/opt4048_ws_static/cie1931_diagram.svg.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// SPDX-FileCopyrightText: Copyright (c) 2009 BenRG
// SPDX-License-Identifier: LicenseRef-Wikipedia-Public-Domain
202 changes: 202 additions & 0 deletions examples/opt4048_ws_static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2025 Tim C for Adafruit Industries
SPDX-License-Identifier: MIT
-->
<!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>
<style>
body {
font-family: Arial, sans-serif;
max-width: 100%;
margin: 0 auto;
padding: 8px;
height: 100vh;
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
flex: 1;
}
.controls {
flex: 1;
min-width: 230px;
max-width: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.visualization {
flex: 2;
min-width: 280px;
max-width: 100%;
display: flex;
flex-direction: column;
}
#cie-diagram {
position: relative;
width: 100%;
max-width: 450px;
margin: 0 auto 10px auto;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
#cie-diagram img {
width: 100%;
max-height: 100%;
object-fit: contain;
display: block;
}
#data-point {
position: absolute;
width: 16px;
height: 16px;
background-color: white;
border-radius: 50%;
border: 3px solid black;
transform: translate(-50%, -50%);
pointer-events: none;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.9);
z-index: 10;
}
#color-sample {
width: 30px;
height: 30px;
border: 1px solid #ccc;
margin: 0 auto;
border-radius: 50%;
}
#serial-log {
flex: 1;
min-height: 80px;
max-height: 150px;
overflow-y: auto;
background-color: #f5f5f5;
padding: 8px;
border: 1px solid #ddd;
font-family: monospace;
font-size: 12px;
margin-bottom: 5px;
}
button {
padding: 8px 12px;
margin: 4px 4px 4px 0;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #45a049;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.data-display {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
margin-top: 10px;
}
.data-box {
flex: 1;
min-width: 100px;
margin: 0;
padding: 10px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
text-align: center;
}
.data-box h3 {
margin: 0 0 5px 0;
font-size: 14px;
}
.data-value {
font-size: 18px;
font-weight: bold;
}

/* Responsive adjustments for very small screens */
@media (max-height: 600px) {
h1 { font-size: 20px !important; margin: 5px 0 !important; }
h2 { font-size: 16px; margin: 8px 0 5px 0; }
p { font-size: 12px !important; margin: 5px 0 !important; }
.data-box { padding: 5px; }
.data-box h3 { font-size: 12px; margin: 0 0 3px 0; }
.data-value { font-size: 14px; }
#serial-log { min-height: 60px; max-height: 100px; }
button { padding: 6px 10px; font-size: 12px; }
}
</style>
</head>
<body>


<div class="container">
<div class="controls">
<h2 style="margin: 10px 0; font-size: 24px;">OPT4048 CIE Color Plotter</h2>
<p style="margin: 8px 0; font-size: 14px;">Connect your Arduino with OPT4048 sensor to visualize color measurements on a CIE diagram.</p>

<button id="clear-button">Clear Log</button>
<button id="test-plot-button" style="display: none;">Test Plot Point</button>

<h2>Connection Status</h2>
<p id="status">Not connected</p>

<h2 style="margin-bottom: 5px;">Serial Monitor</h2>
<div id="serial-log"></div>
</div>

<div class="visualization">
<h2 style="margin: 10px 0; font-size: 24px;">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>
<!-- Debug info: will show exact location of measured color -->
<div id="debug-coordinates" style="position: absolute; bottom: 3px; right: 3px; font-size: 10px; background: rgba(255,255,255,0.7); padding: 2px; border: 1px solid #ccc; display: block;"></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>
Loading