html svg display + websocket

This commit is contained in:
Patrick Haßel 2025-01-09 13:53:44 +01:00
parent 0e93eafb7e
commit 12c089f7b9
5 changed files with 205 additions and 72 deletions

View File

@ -13,7 +13,6 @@
button { button {
width: 33vmin; width: 33vmin;
height: 33vmin;
font-size: 9vw; font-size: 9vw;
} }
@ -29,16 +28,17 @@
td { td {
text-align: center; text-align: center;
} }
</style>
<script> svg {
function get(path) { border: 1px solid black;
var r = new XMLHttpRequest(); width: 100%;
r.open("GET", path, true); height: calc(11 / 27 * 100%);
r.send();
} }
</script> </style>
</head> </head>
<body> <body>
<svg width="800" height="325" id="display">
</svg>
<table> <table>
<tr> <tr>
<td> <td>
@ -67,6 +67,104 @@
</td> </td>
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
<!--suppress PointlessArithmeticExpressionJS -->
<script>
const S = 100 / 27;
const display = document.getElementById("display");
const segments = [];
function get(path) {
const request = new XMLHttpRequest();
request.open("GET", "http://10.0.0.119" + path, true);
request.send();
}
function drawDigit(x, y) {
drawPixel(x, y, 0, 3);
drawPixel(x, y, 0, 2);
drawPixel(x, y, 0, 1);
drawPixel(x, y, 1, 0);
drawPixel(x, y, 2, 0);
drawPixel(x, y, 3, 0);
drawPixel(x, y, 4, 1);
drawPixel(x, y, 4, 2);
drawPixel(x, y, 4, 3);
drawPixel(x, y, 4, 5);
drawPixel(x, y, 4, 6);
drawPixel(x, y, 4, 7);
drawPixel(x, y, 3, 8);
drawPixel(x, y, 2, 8);
drawPixel(x, y, 1, 8);
drawPixel(x, y, 0, 7);
drawPixel(x, y, 0, 6);
drawPixel(x, y, 0, 5);
drawPixel(x, y, 1, 4);
drawPixel(x, y, 2, 4);
drawPixel(x, y, 3, 4);
}
function drawPixel(offsetRasterX, offsetRasterY, innerRasterX, innerRasterY) {
const segment = document.createElementNS("http://www.w3.org/2000/svg", "rect");
const x = (offsetRasterX + innerRasterX) * S;
const y = (offsetRasterY + innerRasterY) * S;
segment.setAttribute("x", x + "vw");
segment.setAttribute("y", y + "vw");
segment.setAttribute("width", S + "vw");
segment.setAttribute("height", S + "vw");
segment.setAttribute("fill", "#555");
segment.setAttribute("id", "segment" + segments.length);
display.appendChild(segment);
segments.push(segment);
}
function drawDisplay(rasterX, rasterY) {
drawDigit(rasterX, rasterY);
rasterX += 6;
drawDigit(rasterX, rasterY);
rasterX += 6;
drawPixel(rasterX, rasterY, 0, 0);
drawPixel(rasterX, rasterY + 2.5, 0, 0);
drawPixel(rasterX, rasterY + 5.5, 0, 0);
drawPixel(rasterX, rasterY + 8, 0, 0);
rasterX += 2;
drawDigit(rasterX, rasterY);
rasterX += 6;
drawDigit(rasterX, rasterY);
}
function connect() {
console.log("connecting websocket...");
const host = "10.0.0.119";
const port = "80";
const url = `ws://${host}:${port}/ws`;
console.log(url);
const socket = new WebSocket(url);
socket.timeout = 1;
socket.addEventListener('open', _ => console.log('websocket connected'));
socket.addEventListener('message', event => {
event.data.split(',').filter((color, index) => color !== '').forEach((color, index) => segments[index].setAttribute("fill", "#" + color));
});
socket.addEventListener('close', _ => {
console.log('websocket disconnected');
connect();
});
}
drawDisplay(1, 1);
connect();
</script>
</table> </table>
</body> </body>
</html> </html>

View File

@ -8,6 +8,8 @@ AsyncWebServer server(80);
AsyncWebSocket ws("/ws"); AsyncWebSocket ws("/ws");
auto websocketStarted = false;
void httpIndex(AsyncWebServerRequest *request) { void httpIndex(AsyncWebServerRequest *request) {
info(request->url().c_str()); info(request->url().c_str());
request->send(LittleFS, "/index.html", "text/html"); request->send(LittleFS, "/index.html", "text/html");
@ -90,8 +92,15 @@ void httpSetup() {
server.on("/action/cancel", HTTP_GET, httpActionCancel); server.on("/action/cancel", HTTP_GET, httpActionCancel);
server.on("/action/confirm", HTTP_GET, httpActionConfirm); server.on("/action/confirm", HTTP_GET, httpActionConfirm);
server.begin(); server.begin();
websocketStarted = true;
} }
void httpLoop() { void httpLoop() {
ws.cleanupClients(); ws.cleanupClients();
} }
void websocketSend(const char *message) {
if (websocketStarted) {
ws.textAll(message);
}
}

View File

@ -5,4 +5,6 @@ void httpSetup();
void httpLoop(); void httpLoop();
void websocketSend(const char *message);
#endif #endif

View File

@ -59,13 +59,14 @@ void logLoop() {
const auto c = static_cast<char>(Serial.read()); const auto c = static_cast<char>(Serial.read());
switch (c) { switch (c) {
case 13: case 13:
Serial.print(c);
execute(cmd); execute(cmd);
write = cmd; write = cmd;
*write = 0; *write = 0;
break; break;
case 8: case 8:
Serial.print(c);
if (write > cmd) { if (write > cmd) {
Serial.print(c);
*write-- = 0; *write-- = 0;
} }
break; break;

View File

@ -7,6 +7,7 @@
#include "Color.h" #include "Color.h"
#include "font.h" #include "font.h"
#include "core/http.h"
#define PIXELS_PER_SEGMENT 3 #define PIXELS_PER_SEGMENT 3
#define SEGMENTS_PER_DIGIT 7 #define SEGMENTS_PER_DIGIT 7
@ -24,7 +25,7 @@ class Display {
// Adafruit_NeoPixel leds; // Adafruit_NeoPixel leds;
Color buffer[PIXEL_COUNT] = {}; Color pixels[PIXEL_COUNT] = {};
Color color = WHITE; Color color = WHITE;
@ -46,12 +47,28 @@ public:
} }
void clear() { void clear() {
memset(buffer, 0, PIXEL_BYTE_COUNT); memset(pixels, 0, PIXEL_BYTE_COUNT);
} }
void flush() { void flush() {
// memcpy(leds.getPixels(), buffer, PIXEL_BYTE_COUNT); // memcpy(leds.getPixels(), buffer, PIXEL_BYTE_COUNT);
// leds.show(); // leds.show();
const auto now = millis();
static auto last = now;
if (now - last >= 500) {
last = now;
send();
}
}
void send() {
char buffer[512];
char *b = buffer;
for (const auto& pixel: pixels) {
b += snprintf(b, sizeof buffer - (b - buffer), "%02X%02X%02X,", pixel.r, pixel.g, pixel.b);
}
websocketSend(buffer);
} }
int printf(const char *format, ...) { int printf(const char *format, ...) {
@ -78,12 +95,18 @@ public:
case '\'': case '\'':
case '"': case '"':
case '`': case '`':
case '.': return printDots(pixel, false, false, false, true); case '.':
case ',': return printDots(pixel, false, false, true, true); return printDots(pixel, false, false, false, true);
case ':': return printDots(pixel, false, true, true, false); case ',':
case ';': return printDots(pixel, false, true, true, true); return printDots(pixel, false, false, true, true);
case '|': return printDots(pixel, true, true, true, true); case ':':
default: return printCharacter(pixel, character); return printDots(pixel, false, true, true, false);
case ';':
return printDots(pixel, false, true, true, true);
case '|':
return printDots(pixel, true, true, true, true);
default:
return printCharacter(pixel, character);
} }
} }
@ -93,19 +116,19 @@ public:
return 0; return 0;
} }
if (dot0) { if (dot0) {
buffer[pixel] = color; pixels[pixel] = color;
} }
pixel++; pixel++;
if (dot1) { if (dot1) {
buffer[pixel] = color; pixels[pixel] = color;
} }
pixel++; pixel++;
if (dot2) { if (dot2) {
buffer[pixel] = color; pixels[pixel] = color;
} }
pixel++; pixel++;
if (dot3) { if (dot3) {
buffer[pixel] = color; pixels[pixel] = color;
} }
return pixel; return pixel;
} }
@ -115,9 +138,9 @@ public:
const auto symbol = getSymbol(character); const auto symbol = getSymbol(character);
for (auto s = *symbol; s < *symbol + SYMBOL_SIZE; s++) { for (auto s = *symbol; s < *symbol + SYMBOL_SIZE; s++) {
if (*s) { if (*s) {
buffer[pixel++] = color; pixels[pixel++] = color;
buffer[pixel++] = color; pixels[pixel++] = color;
buffer[pixel++] = color; pixels[pixel++] = color;
} else { } else {
pixel += 3; pixel += 3;
} }