Инженерная задача
Не выпускать vendor-specific GATT UUID, packet layouts и command bytes наружу и дать остальным сервисам стабильный domain-oriented API.
Не выпускать vendor-specific GATT UUID, packet layouts и command bytes наружу и дать остальным сервисам стабильный domain-oriented API.
Go / Systems Engineer. Я спроектировал service boundary, protobuf contracts, BLE adapters, обработку бинарного протокола, concurrency model, streaming path, retry lifecycle, tests и container setup.
BLE notification → frame assembler → checksum / protocol parser → thread-safe battery state → gRPC unary snapshot или server stream
Рабочий gateway с проверенной на реальном JBD BMS телеметрией, покрытым тестами JDY relay command path, mock mode, Docker, integration tests и CI.
BLE Device Gateway — hardware-facing сервис внутри RV Monitor. Он работает на Linux / Raspberry Pi и превращает device-specific BLE-коммуникацию в небольшой типизированный gRPC boundary. Текущая реализация читает JBD BMS, отдаёт текущее состояние и live server stream, а также реализует управление JDY-33 relay. Основная инженерная работа здесь не CRUD, а реальные edge-условия: фрагментированные бинарные пакеты, общий Bluetooth-адаптер, конкурентные consumers, cancellation, устаревшее состояние и переподключения.

Потребители работают с GetSnapshot, StreamSnapshots и SetChannel вместо ReadCharacteristic или WriteCharacteristic. BLE UUID, vendor packet layouts и command encoding остаются внутри gateway, а внутренняя battery model не зависит от сгенерированных protobuf types. Так hardware-specific детали не протекают в application layer.
Ответ JBD может приходить несколькими BLE notifications. Frame assembler накапливает фрагменты до полного ответа, после чего gateway проверяет framing и checksum и разбирает напряжение, signed current, state of charge, напряжения ячеек, температуры, protection flags и другие параметры аккумулятора. Telemetry path проверен на физическом BMS, установленном в автодоме.
API поддерживает и unary snapshot текущего состояния, и server-streaming telemetry. Каждый subscriber получает небольшой buffered channel, а публикация не блокирует BLE processing: если клиент отстаёт, старое ожидающее значение заменяется самым свежим, потому что для этого сценария актуальное состояние важнее воспроизведения каждой промежуточной точки. Shared state защищён синхронизацией, а BLE discovery сериализован, поскольку оба устройства используют один физический Bluetooth controller.
Долгоживущие hardware clients работают через context-aware retry loop с exponential backoff, а при потере BMS telemetry становится unavailable вместо выдачи старого snapshot как актуального. Shutdown прокидывается через context cancellation и bounded gRPC graceful stop. Mock source без железа, Docker / Compose, gRPC integration tests через bufconn, race-detector checks и GitHub Actions позволяют запускать и проверять тот же public API без автодома.