Сервис FastAPI (LAN + BLE)¶
HTTP API для дашбордов, скриптов или мобильных приложений: FastAPI + OpenAPI на /docs, панель управления в браузере на / и планировщик asyncio (слоты Function по моторам, сессии preset/pattern, GET /tasks). Реализация — lovensepy.services.http_api (импорт lovensepy.services.fastapi сохранён для совместимости): в LAN используется Game Mode (AsyncLANClient); в BLE — BleDirectHub; в hybrid несколько транспортов одновременно. Все бэкенды удовлетворяют LovenseControlBackend, протоколу, согласованному с поверхностью LovenseAsyncControlClient, которую использует планировщик (см. Справочник API — LovenseAsyncControlClient).
Просто хочется управлять игрушками?
Запустите сервис и откройте http://127.0.0.1:8000/ — встроенная панель сама найдёт, подключит и будет управлять. Эта страница — про работу с API напрямую.
Требования¶
LAN-режим (по умолчанию)¶
Окружение¶
export LOVENSE_LAN_IP=192.168.1.100 # хост с Lovense Remote (Game Mode)
export LOVENSE_SERVICE_MODE=lan # по умолчанию; можно опустить
# опционально: LOVENSE_LAN_PORT=20011 LOVENSE_APP_NAME=... LOVENSE_TOY_IDS=id1,id2
# опционально: LOVENSE_SESSION_MAX_SEC=60 # строка /tasks при time=0 у preset/pattern
Запуск сервера¶
Устаревшая обёртка (предупреждение при импорте):
Программная настройка¶
from lovensepy.services import ServiceConfig, create_app
app = create_app(ServiceConfig(mode="lan", lan_ip="192.168.1.100"))
Колбэки BLE-рекламы (только BLE-режим, см. ниже): передайте on_ble_advertisement и/или on_ble_advertisement_async в create_app(...).
BLE-режим¶
Вместо Game Mode — прямой BLE. На старте ничего не подключено: вызовите POST /ble/connect/auto для сценария «просто работает» либо сканируйте и подключайте по адресу через POST /ble/connect (или колбэки для BleDirectHub.add_toy / connect).
export LOVENSE_SERVICE_MODE=ble
# опционально: LOVENSE_BLE_SCAN_TIMEOUT=8 LOVENSE_BLE_SCAN_PREFIX=LVS- (пустой префикс = все имена)
# опционально пассивные обновления RSSI: LOVENSE_BLE_ADVERT_MONITOR=1 LOVENSE_BLE_ADVERT_MONITOR_INTERVAL=2
# опционально пресеты: LOVENSEPY_BLE_PRESET_UART=Pat (как у BleDirectClient по умолчанию; сервис по умолчанию Preset для /command/preset)
# опционально: LOVENSEPY_BLE_PRESET_EMULATE_PATTERN=1 (pulse/wave/… через паттерн, если UART пресеты игнорируются)
# опционально: LOVENSE_BLE_AUTO_RECONNECT=0 (не держать зарегистрированные игрушки подключёнными)
uvicorn lovensepy.services.http_api.app:app --host 0.0.0.0 --port 8000
Дополнительные HTTP-маршруты (только BLE):
POST /ble/scan— скан по запросу; querytimeoutопционально; ответ:address,name,rssiGET /ble/advertisements— последняя карта рекламы (сканы плюс опциональный монитор)GET /ble/toys— вид регистраций: адрес, состояние связи, кэш метаданных UART, статус автопереподключенияPOST /ble/connect— тело:address, опциональноtoy_id,name,toy_type,replacePOST /ble/connect/auto— скан, подключение всего, что ответило, и переподключение зарегистрированных; вся настройка одним вызовомPOST /ble/reconnect/{toy_id}— переподключение со снятием паузы после ручного отключенияPOST /ble/disconnect/{toy_id}— отключение GATT (регистрация остаётся, автопереподключение встаёт на паузу)DELETE /ble/toys/{toy_id}— отключение и снятие регистрации
GET /toys и командные маршруты совпадают с LAN после подключения игрушек. Зарегистрированные игрушки сервис держит подключёнными в фоне с экспоненциальной задержкой на игрушку (LOVENSE_BLE_AUTO_RECONNECT=0 — выключить); текущее состояние — в GET /state → ble.supervisor.
Состояние одним запросом, обновления одним сокетом¶
GET /state— игрушки, объединённые по транспортам, активные строки планировщика, обнаружение BLE и статус супервизора, состояние привязки Socket API, возможности и конфигурация. Список игрушек кэшируется наLOVENSE_STATE_CACHE_TTLсекунд (по умолчанию 2);?fresh=trueобходит кэш. Дашборду стоит опрашивать именно этот эндпоинт вместо/toysв цикле: по BLE каждыйGET /toysсbattery=trueстоит UART-обмена на устройство.WS /ws— тот же снимок при каждом изменении, в простое — heartbeat.{"op": "refresh"}— немедленный свежий снимок,{"op": "ping"}— ответ{"type": "pong"}.GET /system/network— адреса, по которым доступен сервис (для QR-кода «открыть на телефоне»).
Настройка на ходу¶
Без перезапуска и переменных окружения:
POST /config/lan-ip—{"lan_ip": "192.168.1.100", "lan_port": 20011}включает LAN на местеPOST /config/socket— учётные данные Socket API (только в памяти, на диск не пишутся)POST /config/ble— автопереподключение, фоновый скан, фильтр скана, диалект пресетовPOST /config/transports—{"lan": true, "ble": false}для переключения транспортовGET /config— текущая конфигурация без секретов
Эндпоинты выключенного транспорта отвечают 409, чтобы клиент отличал «выключено» от «нет такого маршрута».
OpenAPI¶
Откройте http://127.0.0.1:8000/docs (ReDoc на /redoc) и попробуйте GET /state, POST /command/preset, GET /tasks и эндпоинты стопа (/command/stop/... и пакетные варианты).
Замечания по поведению¶
- BLE: паттерны (и зацикленный
Function) могут удерживать работу, пока :class:~lovensepy.ble_direct.client.BleDirectClientшагает по UART. Пресеты в этом сервисе по умолчанию через UARTPreset:{n};(LOVENSEPY_BLE_PRESET_UART=Pat— как у прямого BLE-клиента по умолчанию). СLOVENSEPY_BLE_PRESET_EMULATE_PATTERN=1четыре имени приложения идут через шаги паттерна (как/command/pattern). Таймированные пресеты приwait_for_completion=Falseоткладывают удержание + stop burst. У прямого :class:~lovensepy.ble_direct.client.BleDirectClientпо умолчаниюwait_for_completion=True. - Повторная отправка того же пресета или паттерна для той же игрушки продлевает сессию и шлёт ещё одну транспортную команду с новым
time(Lovense иначе гасит послеtimeSecкаждой команды). - Сервис запускается даже когда транспорт недоступен (нет LAN IP, нет
bleak, нет учётных данных Socket): его эндпоинты отвечают 409, пока вы не настроите их через/config/*или панель. В health-only режим сервис уходит только при действительно сломанной конфигурации окружения. GET /tasksвозвращает строки function (kind: function), function_loop приloop_on_time/loop_off_timeуPOST /command/function, и preset / pattern (kind: preset/pattern). В метках времени естьstarted_at(UTC) иstarted_monotonic_secдля стабильногоremaining_sec.
См. также страницу Веб-панель управления и строку Примеры про HTTP-сервис.