Skip to content

Commit

Permalink
Fix arduino websockets poll lag. Adding weather.
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewmunro committed Feb 2, 2024
1 parent 7e09c9b commit 8286ed6
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 191 deletions.
13 changes: 4 additions & 9 deletions arduino/bitmapstream.ino
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ using namespace websockets;
MatrixPanel_I2S_DMA* dma_display;
WebsocketsClient client;

void onMessageCallback(WebsocketsMessage message) {
uint16_t* uint16_data = (uint16_t *) message.c_str();
dma_display->drawRGBBitmap(0, 0, uint16_data, 128, 32);
}

void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionOpened) {
Serial.println("Connnection Opened");
Expand Down Expand Up @@ -68,9 +63,6 @@ void setup() {
delay(2000);
ESP.restart();
}

// run callback when messages are received
client.onMessage(onMessageCallback);

// run callback when events are occuring
client.onEvent(onEventsCallback);
Expand All @@ -91,5 +83,8 @@ void setup() {
}

void loop() {
client.poll();
auto message = client.readBlocking();

uint16_t* uint16_data = (uint16_t *) message.c_str();
dma_display->drawRGBBitmap(0, 0, uint16_data, 128, 32);
}
21 changes: 9 additions & 12 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>DotMatrix Sandbox</title>
<meta charset="UTF-8" />
</head>

<head>
<title>DotMatrix Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>

<body>
<div id="app"></div>

<script type="module" src="src/client.ts">
</script>
</body>

</html>
<script type="module" src="src/sender.ts"></script>
</body>
</html>
45 changes: 45 additions & 0 deletions src/reciever.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { rgb565ToRGBA } from './utils';

const canvas = document.createElement('canvas');
canvas.width = 1280;
canvas.height = 320;
canvas.style = 'zoom: 10';
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;

let hasDisconnected = false;

const connect = () => {
const ws = new WebSocket(`ws://rgb.mun.sh/sub`);
ws.onopen = evt => {
console.log('connected!', evt);

if (hasDisconnected) {
// Force refresh to get new client
window.location.reload();
}
};

ws.onmessage = async evt => {
const data = (await evt.data.arrayBuffer()) as ArrayBuffer;
const rgba = rgb565ToRGBA(new Uint16Array(data));
const imageData = new ImageData(new Uint8ClampedArray(rgba), 128, 32);

ctx.putImageData(imageData, 0, 0);
};

ws.onerror = ws.onclose = () => {
console.log('websocket closed! refreshing!');

hasDisconnected = true;

setTimeout(() => {
connect();
}, 1000);
};
};

// Draw to RGB
setTimeout(() => {
connect();
}, 1000);
70 changes: 35 additions & 35 deletions src/client.ts → src/sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import { BaseTexture, Container, Program, Renderer, RenderTexture, Sprite } from
import { dotMatrixFilter, rgbaToRgb565 } from './utils';
import { clock } from './views/clock';
import { transportScreen } from './views/transportScreen';
import { weather } from './views/weather';

BaseTexture.defaultOptions.scaleMode = PIXI.SCALE_MODES.NEAREST;
Program.defaultFragmentPrecision = PIXI.PRECISION.HIGH;

const app = new PIXI.Application({
width: 1280,
height: 320,
resolution: 1,
forceCanvas: true,
width: 1280,
height: 320,
resolution: 1,
forceCanvas: false
});
document.body.appendChild(app.view as any);

Expand All @@ -31,51 +32,50 @@ display.addChild(transportScreen());
// app.ticker.add((await gifs(display)).update);
// app.ticker.add((await scrollingText(display)).update);
// app.ticker.add(await scrollingDot(display));
display.addChild(weather());
app.ticker.add((await clock(display)).update);

// Render
app.ticker.add(delta => {
renderer.render(display, { renderTexture });
renderer.render(app.stage);
renderer.render(display, { renderTexture });
renderer.render(app.stage);
});

let hasDisconnected = false;

const connect = () => {
const ws = new WebSocket(`ws://${location.host}/pub`);
ws.onopen = evt => {
console.log('connected!', evt);
const ws = new WebSocket(`ws://${location.host}/pub`);
ws.onopen = evt => {
console.log('connected!', evt);

if (hasDisconnected) {
// Force refresh to get new client
window.location.reload();
} else {
setInterval(() => {
const pixels = renderer.extract.pixels(renderTexture);
const rgb565 = rgbaToRgb565(pixels);
ws.send(rgb565);
}, 1000 * 1 / app.ticker.maxFPS);
}
};
if (hasDisconnected) {
// Force refresh to get new client
window.location.reload();
} else {
setInterval(() => {
const pixels = renderer.extract.pixels(renderTexture);
const rgb565 = rgbaToRgb565(pixels);
ws.send(rgb565);
}, (1000 * 1) / app.ticker.maxFPS);
}
};

ws.onmessage = evt => {
console.log('message!', evt);
};
ws.onmessage = evt => {
console.log('message!', evt);
};

ws.onclose = () => {
console.log('websocket closed! refreshing!');
ws.onclose = () => {
console.log('websocket closed! refreshing!');

hasDisconnected = true;
setTimeout(() => {
connect();
}, 1000);
};
}
hasDisconnected = true;

setTimeout(() => {
connect();
}, 1000);
};
};

// Draw to RGB
setTimeout(() => {
connect();

connect();
}, 1000);

47 changes: 45 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ const app = bunExpress({
}

if (ws.data.url.pathname == '/sub') {
subSockets.push(ws);
setTimeout(() => {
subSockets.push(ws);
}, 500);

console.log('new subscriber', ws.data.id);
}
},
Expand Down Expand Up @@ -62,7 +65,7 @@ const app = bunExpress({
}
} as WebSocketServeOptions<WebSocketData> as any);

const sendInterval = process.env.SEND_INTERVAL ? parseInt(process.env.SEND_INTERVAL) : 500;
const sendInterval = process.env.SEND_INTERVAL ? parseInt(process.env.SEND_INTERVAL) : 100;

// Throttle updates to RGB screen
setInterval(() => {
Expand Down Expand Up @@ -202,6 +205,46 @@ app.get('/api/flights/arrivals', async (req, res) => {
res.json(flights);
});

function mapWeatherToEmoji(wmoCode: number): string {
switch (wmoCode) {
case 0: // Clear sky
return '☀️';
case 1: // Partly cloudy
case 2:
return '⛅';
case 3: // Cloudy
return '☁️';
case 10: // Mist
case 20: // Fog
return '🌫️';
case 30: // Drizzle
case 40: // Rain
return '🌧️';
case 60: // Thunderstorm
return '⛈️';
case 80: // Snow
return '❄️';
default:
return '❓'; // Unknown or unsupported weather condition
}
}

app.get('/api/weather', async (req, res) => {
const lat = '53.8193';
const long = '-1.5990';
const response = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${long}&current=temperature_2m,weather_code`
);

const data = await response.json();

const temp = Math.round(data.current.temperature_2m);
const weatherCode = data.current.weather_code;
const emoji = mapWeatherToEmoji(weatherCode);

res.json({ temp, emoji });
});

app.listen(3000, () => {
console.log('server started on', 3000);
});
19 changes: 19 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,25 @@ export function rgbaToRgb565(rgba: Uint8Array) {
return rgb565;
}

export function rgb565ToRGBA(rgb565: Uint16Array) {
const length = rgb565.length;
const rgba = new Uint8Array(length * 4);

for (let i = 0; i < length; i++) {
const rgb = rgb565[i];
const r = ((rgb >> 11) * 255) / 31;
const g = (((rgb >> 5) & 0x3f) * 255) / 63;
const b = ((rgb & 0x1f) * 255) / 31;

rgba[i * 4] = r;
rgba[i * 4 + 1] = g;
rgba[i * 4 + 2] = b;
rgba[i * 4 + 3] = 255;
}

return rgba;
}

const dotMatrixShader = `
precision mediump float;
Expand Down
Loading

0 comments on commit 8286ed6

Please sign in to comment.