pipenv: add send-net; networking: use SPI; add networking test

This commit is contained in:
Pi User
2025-10-01 23:10:56 +13:00
parent f9188b694e
commit ed35d6b838
3 changed files with 176 additions and 31 deletions

View File

@@ -1,53 +1,79 @@
import asyncio
import websockets
import json
import os
import time
try:
import spidev
except Exception as e:
spidev = None
class WebSocketClient:
def __init__(self, uri):
self.uri = uri
self.websocket = None
def __init__(self, uri=None, *, bus=None, device=None, speed_hz=None):
# SPI configuration (defaults can be overridden by args or env)
self.bus = 0 if bus is None else int(bus)
self.device = 0 if device is None else int(device)
self.speed_hz = (
int(os.getenv("SPI_SPEED_HZ", "1000000")) if speed_hz is None else int(speed_hz)
)
self.spi = None
self.is_connected = False
async def connect(self):
"""Establishes the WebSocket connection."""
if self.is_connected and self.websocket:
print("Already connected.")
"""Initializes the SPI connection."""
if self.is_connected and self.spi:
return
if spidev is None:
print("spidev not available; cannot open SPI")
self.is_connected = False
self.spi = None
return
try:
print(f"Connecting to {self.uri}...")
self.websocket = await websockets.connect(self.uri)
spi = spidev.SpiDev()
spi.open(self.bus, self.device)
spi.max_speed_hz = self.speed_hz
spi.mode = 0
spi.bits_per_word = 8
self.spi = spi
self.is_connected = True
print("WebSocket connected.")
except (ConnectionError, websockets.exceptions.ConnectionClosedOK) as e:
print(f"Error connecting: {e}")
print(f"SPI connected: bus={self.bus} device={self.device} speed={self.speed_hz}Hz mode=0")
except Exception as e:
print(f"Error opening SPI: {e}")
self.is_connected = False
self.websocket = None
self.spi = None
async def send_data(self, data):
print(data)
"""Sends data over the open WebSocket connection."""
if not self.is_connected or not self.websocket:
print("WebSocket not connected. Attempting to reconnect...")
"""Sends a JSON object over SPI as UTF-8 bytes."""
if not self.is_connected or not self.spi:
await self.connect()
if not self.is_connected:
print("Failed to reconnect. Cannot send data.")
print("SPI not connected; cannot send")
return
try:
await self.websocket.send(json.dumps(data))
print(f"Sent: {data}")
except (ConnectionError, websockets.exceptions.ConnectionClosed) as e:
print(f"Error sending data: {e}")
json_str = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
payload = list(json_str.encode("utf-8"))
if not payload:
return
# Keep payload comfortably below ESP-NOW max; trim if necessary
if len(payload) > 240:
payload = payload[:240]
self.spi.xfer2(payload)
except Exception as e:
print(f"SPI send failed: {e}")
# Attempt simple reopen on next call
self.is_connected = False
self.websocket = None # Reset connection on error
await self.connect() # Attempt to reconnect
self.spi = None
async def close(self):
"""Closes the WebSocket connection."""
if self.websocket and self.is_connected:
await self.websocket.close()
self.is_connected = False
self.websocket = None
print("WebSocket closed.")
"""Closes the SPI connection."""
try:
if self.spi:
self.spi.close()
except Exception:
pass
self.is_connected = False
self.spi = None