pipenv: add send-net; networking: use SPI; add networking test
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user