mirror of
https://github.com/justLV/onju-v2
synced 2026-04-21 15:47:55 +00:00
Pipeline: async voice pipeline replacing monolithic threaded server. ASR, LLM, and TTS are independent pluggable services. ASR calls external parakeet-asr-server, LLM uses any OpenAI-compatible endpoint, TTS uses ElevenLabs with pluggable backend interface. Firmware: add mDNS hostname resolution as fallback when multicast discovery doesn't work. Resolves configured server_hostname via MDNS.queryHost() on boot, falls back to multicast if resolution fails. Also adds test_client.py that emulates an ESP32 device for testing without hardware (TCP server, Opus decode, mic streaming).
55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
import asyncio
|
|
import logging
|
|
import struct
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
async def send_tcp(ip: str, port: int, header: bytes, data: bytes | None = None, timeout: float = 60):
|
|
try:
|
|
reader, writer = await asyncio.wait_for(
|
|
asyncio.open_connection(ip, port), timeout=5
|
|
)
|
|
writer.write(header)
|
|
if data:
|
|
writer.write(data)
|
|
await writer.drain()
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
except asyncio.TimeoutError:
|
|
log.error(f"TCP timeout to {ip}:{port}")
|
|
except Exception as e:
|
|
log.error(f"TCP error to {ip}:{port}: {e}")
|
|
|
|
|
|
async def send_audio(ip: str, port: int, opus_payload: bytes, mic_timeout: int = 60, volume: int = 14, fade: int = 6):
|
|
# header[0] 0xAA for audio
|
|
# header[1:2] mic timeout in seconds (big-endian)
|
|
# header[3] volume
|
|
# header[4] fade rate
|
|
# header[5] compression type (2 = Opus)
|
|
header = bytes([
|
|
0xAA,
|
|
(mic_timeout >> 8) & 0xFF,
|
|
mic_timeout & 0xFF,
|
|
volume,
|
|
fade,
|
|
2, # Opus
|
|
])
|
|
await send_tcp(ip, port, header, opus_payload)
|
|
|
|
|
|
async def send_led_blink(ip: str, port: int, intensity: int, r: int = 255, g: int = 255, b: int = 255, fade: int = 6):
|
|
# header[0] 0xCC for LED blink
|
|
# header[1] starting intensity
|
|
# header[2:4] RGB
|
|
# header[5] fade rate
|
|
header = bytes([0xCC, intensity, r, g, b, fade])
|
|
await send_tcp(ip, port, header, timeout=0.1)
|
|
|
|
|
|
async def send_stop_listening(ip: str, port: int):
|
|
# header[0] 0xDD for mic timeout
|
|
# header[1:2] timeout = 0 (stop)
|
|
header = bytes([0xDD, 0, 0, 0, 0, 0])
|
|
await send_tcp(ip, port, header, timeout=0.2)
|