diff --git a/light_service.py b/light_service.py index 10065b0..80b9cdb 100644 --- a/light_service.py +++ b/light_service.py @@ -15,9 +15,11 @@ API: POST /state - Set state {"state": "listening"} POST /jaw/level - Set jaw level {"level": 0-100} POST /jaw/mode - Set jaw mode {"mode": "talking"} + UDP :8782 - Jaw amplitude (bare integer, fire-and-forget lip sync) """ import time +import socket import threading import json import signal @@ -26,6 +28,7 @@ import serial # === Configuration === HTTP_PORT = 8781 +UDP_PORT = 8782 SERIAL_PORT = "/dev/ttyACM0" SERIAL_BAUD = 115200 @@ -152,6 +155,24 @@ class LightAPIHandler(BaseHTTPRequestHandler): self.send_header('Access-Control-Allow-Headers', 'Content-Type') self.end_headers() +# === UDP Amplitude Listener === +def run_udp_listener(): + """Listen for jaw amplitude via UDP (fire-and-forget from voice service).""" + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.bind(('0.0.0.0', UDP_PORT)) + sock.settimeout(1.0) + print(f"[LIGHT] UDP listener on port {UDP_PORT}") + while running: + try: + data, _ = sock.recvfrom(16) + level = max(0, min(100, int(data))) + send_amplitude(level) + except socket.timeout: + continue + except (ValueError, Exception): + pass + sock.close() + # === Signal Handler === def signal_handler(sig, frame): global running @@ -173,6 +194,10 @@ def main(): # Set initial mood on Pico send_mode_command("mood idle") + # Start UDP listener for lip sync amplitude + udp_thread = threading.Thread(target=run_udp_listener, daemon=True) + udp_thread.start() + server = HTTPServer(('0.0.0.0', HTTP_PORT), LightAPIHandler) print(f"[LIGHT] HTTP API listening on port {HTTP_PORT}") print("[LIGHT] Service ready")