Skip to content

Commit 87d046f

Browse files
committed
Merge dev-main into main: resolve conflicts using dev-main as reference
2 parents 5b612b8 + b9d6348 commit 87d046f

91 files changed

Lines changed: 453994 additions & 17265 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,7 @@ ENV/
223223
.idea/workspace.xml
224224
/.idea
225225
node_modules/
226+
pecan/Frontend/pecan-live-dashboard/src/assets/local.dbc
227+
228+
*.dbc:Zone.Identifier
229+
*.csv:Zone.Identifier

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Western Formula Racing Data Acquisition Dashboard and Radio Communication System
2+
3+
## Project Components
4+
5+
### PECAN
6+
PECAN is a React based
7+
8+
### Vehicle Telemetry Firmware
9+
10+
### Base Station
11+

base-station/docker-compose.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
services:
2+
base-station:
3+
build: .
4+
network_mode: host
5+
restart: unless-stopped
6+
7+
redis:
8+
image: redis:8.2
9+
# network_mode: host
10+
restart: unless-stopped
11+
ports:
12+
- "6379:6379"
13+
volumes:
14+
- redis_data:/data
15+
16+
volumes:
17+
redis_data:

base-station/redis_ws_bridge.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import asyncio
2+
import redis.asyncio as redis
3+
import websockets
4+
import os
5+
import signal
6+
7+
# Config
8+
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
9+
REDIS_CHANNEL = "can_messages"
10+
WS_PORT = int(os.getenv("WS_PORT", 9080))
11+
12+
connected_clients = set()
13+
shutdown_event = asyncio.Event()
14+
15+
async def redis_listener():
16+
"""Listens to Redis and broadcasts to all WS clients."""
17+
try:
18+
r = redis.from_url(REDIS_URL)
19+
pubsub = r.pubsub()
20+
await pubsub.subscribe(REDIS_CHANNEL)
21+
print(f"[*] Subscribed to Redis channel: {REDIS_CHANNEL}")
22+
23+
async for message in pubsub.listen():
24+
if shutdown_event.is_set():
25+
break
26+
27+
if message['type'] == 'message':
28+
data = message['data']
29+
if isinstance(data, bytes):
30+
data = data.decode('utf-8')
31+
32+
# Broadcast to all connected clients
33+
if connected_clients:
34+
# Create tasks for sending to each client to avoid blocking
35+
await asyncio.gather(
36+
*[client.send(data) for client in connected_clients],
37+
return_exceptions=True
38+
)
39+
except Exception as e:
40+
print(f"[!] Redis error: {e}")
41+
finally:
42+
print("[*] Redis listener stopping...")
43+
44+
async def ws_handler(websocket):
45+
"""Manages WebSocket connections."""
46+
connected_clients.add(websocket)
47+
client_info = f"{websocket.remote_address[0]}:{websocket.remote_address[1]}"
48+
print(f"[+] Client connected: {client_info}. Total: {len(connected_clients)}")
49+
50+
try:
51+
await websocket.wait_closed()
52+
except Exception as e:
53+
print(f"[!] Error while waiting for websocket {client_info} to close: {e}")
54+
finally:
55+
connected_clients.remove(websocket)
56+
print(f"[-] Client disconnected: {client_info}. Total: {len(connected_clients)}")
57+
58+
async def main():
59+
loop = asyncio.get_running_loop()
60+
61+
# Handle graceful shutdown
62+
def handle_signal():
63+
print("\n[*] Shutting down...")
64+
shutdown_event.set()
65+
66+
for sig in (signal.SIGINT, signal.SIGTERM):
67+
loop.add_signal_handler(sig, handle_signal)
68+
69+
print(f"[*] Starting WebSocket Bridge on port {WS_PORT}...")
70+
71+
# Start WebSocket server
72+
async with websockets.serve(ws_handler, "0.0.0.0", WS_PORT):
73+
print(f"[*] WebSocket server running at ws://0.0.0.0:{WS_PORT}")
74+
75+
# Run Redis listener until shutdown
76+
await redis_listener()
77+
78+
if __name__ == "__main__":
79+
try:
80+
asyncio.run(main())
81+
except KeyboardInterrupt:
82+
print("\n[*] Keyboard interrupt received, exiting...")

base-station/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
psutil
2+
requests
3+
redis
4+
websockets
5+
cantools

0 commit comments

Comments
 (0)