- Заменена CSS сфера на dotlottie-player
- Анимация реагирует на состояния (idle/listening/speaking)
- Скорость анимации зависит от RMS уровня микрофона
- Добавлена обработка ошибок загрузки
- Сохранены все WebSocket команды и события
- satellite.py: разделён _runtime_volume на _runtime_mic_volume и _runtime_snd_volume
- satellite.py: добавлены команды start_recording/stop_recording (WAV через base64)
- satellite.py: метод _create_wav_from_buffer() для создания WAV из буфера
- web-client: добавлен слайдер громкости микрофона (MIC+/MIC-)
- web-client: добавлены кнопки записи и воспроизведения аудио
- web-client: улучшенный лог событий и отладочные console.log
- docs: websocket-server-plan.md сокращён с 1205 до ~80 строк
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Проблема:
- audio-level спамит 10 раз в секунду
- Не видно других команд (volume, mute, etc.)
Решение:
- Фильтровать audio-level в _broadcast_to_websocket
- Фильтровать audio-level в handle_websocket
- Показывать только важные команды
Результат:
✅ Видны команды: set_volume, mute, unmute, play_sound, etc.
✅ Не видны: audio-level (спам)
✅ Чистые логи для отладки
Проблема: websockets библиотека логирует каждое сообщение:
DEBUG:websockets.server:> TEXT '{"type": "audio-level"...'
Решение: Установить уровень логирования websockets.server в WARNING
logging.getLogger('websockets.server').setLevel(logging.WARNING)
Результат:
- ✅ Пропадут DEBUG сообщения о каждом WebSocket сообщении
- ✅ Останутся только важные ошибки (WARNING/ERROR)
- ✅ Чистые логи для отладки других функций
Изменения:
1. Поле для ввода WebSocket адреса (вместо prompt)
- wsUrlInput с значением по умолчанию
- Сохраняется между перезагрузками
2. Кнопка CONNECT/DISCONNECT
- Меняет текст и цвет при подключении
- DISCONNECT красная кнопка
- Работают обе кнопки (в шапке и в карточке)
3. Auto-connect
- Чекбокс 'Auto-connect on load'
- Автоматическое подключение при загрузке
- Можно отключить
4. updateConnectButton()
- Обновляет обе кнопки синхронно
- 🔌 CONNECT / 🔌 DISCONNECT
Реализована точно такая же анимация как была:
- avg = currentRms * 100 (вместо микрофона)
- Сглаживание rmsSmoothed * 0.7 + avg * 0.3
- Симуляция если RMS < 1 (12 + random * 25)
- Усиление при LISTEN/SPEAK (45 + random * 55)
- 42 столбика с синусом
- Случайные колебания 0.5 + random * 0.3
- Увеличение при SPEAK
Теперь 1-в-1 как оригинал, но с данными satellite!
Изменения:
- 42 столбика как в оригинале
- Синусоидальная анимация
- Градиент cyan → blue
- Сглаживание RMS (0.7 old + 0.3 new)
- Случайные колебания для живости
Теперь красиво как было, но с данными satellite RMS!
Изменения:
- Удалён локальный микрофон (initMicVisualizer)
- Canvas рисует RMS историю от satellite
- 64 столбика с градиентом (зелёный → красный)
- Меньше логов (только если RMS > 0.05)
Преимущества:
- ✅ Показывает реальную громкость satellite
- ✅ Нет зависимости от микрофона браузера
- ✅ Меньше спама в логах
Проблема: rmsFill/rmsValue null до загрузки DOM
Решение:
- Проверка if (!rmsFill || !rmsValue) return
- Инициализация после window.load
- Логирование для отладки
Проблема: updateRmsMeter is not defined
Решение:
- Добавлена функция updateRmsMeter(level)
- Добавлены DOM элементы rmsFill, rmsValue
- Добавлена переменная rmsTimeout
Теперь audio-level события обрабатываются корректно
Проблема: bytes literal с Unicode символами (🔐, ╔, ║ и т.д.)
Решение:
- HTML response через .encode('utf-8') вместо bytes literal
- ASCII box drawing вместо Unicode символов
- Убраны emoji из print statements
Тест:
python3 -m py_compile web-client/start_server.py
Проблемы:
- signal_handler блокировал shutdown()
- Порт не освобождался после Ctrl+C
- Невозможно было перезапустить сервер
Решения:
- Убран signal_handler — используется KeyboardInterrupt
- shutdown() вызывается в отдельном потоке (avoid deadlock)
- with контекст для автоматического закрытия
- allow_reuse_address = True для быстрого рестарта
- Обработка OSError при занятом порте
Исправления:
- fix: баг volume/level — поддерживаются оба названия параметра
- docs: добавлен раздел Web Client в websocket-server-plan.md
- docs: создан web-client/README.md с полной документацией
Функции Web клиента:
- ✅ set_volume (громкость) — работает
- ✅ mute/unmute — работает
- ⏳ audio-level RMS — требует тестирования
- ⏳ LED управление — требует тестирования
- ⏳ Transcript — требует тестирования
Этапы разработки:
- WC-1: Базовая интеграция ✅
- WC-2: Визуализация (в процессе)
- WC-3: Дополнительные функции
- WC-4: UI/UX
- signal_handler вызывает shutdown() который блокируется
- Убран sys.exit(0) из signal handler
- serve_forever() завершается через KeyboardInterrupt
- finally закрывает сокет корректно
- IndexError в log_message — убран неправильный формат
- Ctrl+C не работал — добавлен signal_handler
- Порт не освобождался — добавлен server_close()
- allow_reuse_address=True — для быстрого рестарта
- Добавлен remote URL в баннер
- Статус: В разработке → 🔄 Тестирование
- Добавлено: WebSocket события работают (synthesize, audio-start/stop, played)
- Добавлено: TEST сервисы созданы
- Добавлено: Критический баг исправлен (detach_kernel_driver)
- Требуется тестирование: Audio level monitoring, WebSocket команды
Проблема: detach_kernel_driver(0) отключал ядро от интерфейса 0,
который является частью audio function (интерфейсы 0-2).
После этого audio драйвер не мог восстановить устройство.
Решение: Убрать detach_kernel_driver() вообще.
Control transfer с CTRL_TYPE_VENDOR работает без claim interface.
Так работает xvf_host.py — там тоже нет detach_kernel_driver().
Исправленные файлы:
- wyoming_satellite/xvf_usb.py (уже было исправлено)
- examples/example_led.py
DoA эффект:
- base_color: 0x303030 (серый, без масштабирования)
- doa_color: 0xD4BC00 (бирюзовый, без масштабирования)
- brightness: управляется отдельно через set_led_brightness()
Это как в оригинале до изменений яркости.
Проблема: устройство может быть не готово к командам сразу после
подключения, что вызывает USB reset.
Решение: time.sleep(0.5) после нахождения устройства.
Проблема: detach_kernel_driver(0) отключает ядро от интерфейса 0,
который является частью audio function (интерфейсы 0-2).
Решение: Убрать detach_kernel_driver() вообще.
Control transfer с CTRL_TYPE_VENDOR работает без claim interface
и не требует отключения ядра.
Это как в xvf_host.py — там тоже нет detach_kernel_driver().
Проблема: после перехода на set_led_doa_color() яркость
не устанавливалась отдельно, поэтому LED не работали.
Решение:
- led_controller.set_led_brightness(brightness) после set_led_doa_color()
Восстановлено поведение как в оригинале:
LED_EFFECT [4] → LED_DOA_COLOR → LED_BRIGHTNESS
- services/test/*.service — удалены wake word и event test сервисы
- services/test/wyoming-satelite-vosk-test.service — использует production порты
- install_test_services.sh — обновлён для одного сервиса
- services/test/start_test.sh — запуск только satellite
- docs/deployment/systemd-services.md — обновлена документация
Test satellite использует:
- Production wake word (:10400)
- Production event (:10500)
- Те же порты что и production (:10700)
- WebSocket :8675 + Audio Level (новые функции)