Skip to main content

Overview

This document describes the Bluetooth Low Energy (BLE) protocol used to communicate between the Omi app and device. Use this reference when building custom apps or SDKs.

BLE Discovery

The official app discovers the device by scanning for BLE devices with the name Omi.

BLE Services

The Omi wearable implements three BLE services:

Battery Service

Standard BLE battery level monitoring

Device Info Service

Device metadata and firmware version

Audio Service

Audio streaming and codec configuration

Battery Service

Battery notifications require firmware v1.5 or later. Earlier versions (1.0.x) do not support notifications.
PropertyValue
Service UUID0x180F (standard)
Characteristic UUID0x2A19 (Battery Level)
Supports NotificationsYes (firmware v1.5+)
This is the standard BLE Battery Service.

Device Information Service

Available since firmware version 1.0.3
PropertyValue
Service UUID0x180A (standard)
This is the standard BLE Device Information Service.

Characteristics

CharacteristicUUIDValue
Manufacturer Name0x2A29”Based Hardware”
Model Number0x2A24”Omi”
Hardware Revision0x2A27”Seeed Xiao BLE Sense”
Firmware Revision0x2A26e.g., “1.0.3”

Audio Streaming Service

This is the main service for streaming audio from the device to the app.
PropertyValue
Service UUID19B10000-E8F2-537E-4F6C-D104768A1214

Characteristics

CharacteristicUUIDPurpose
Audio Data19B10001-E8F2-537E-4F6C-D104768A1214Audio stream from device
Codec Type19B10002-E8F2-537E-4F6C-D104768A1214Audio codec identifier

Codec Types

The codec type characteristic determines how to decode the audio data:
ValueCodecSample RateBit Depth
0PCM16 kHz16-bit mono
1PCM8 kHz16-bit mono
10Mu-law16 kHz8-bit mono
11Mu-law8 kHz8-bit mono
20Opus16 kHz16-bit mono
Starting with firmware v1.0.3, the default codec is Opus. Earlier versions used PCM 16-bit at 8 kHz.

Audio Data Format

Audio data is sent as BLE notifications on the Audio Data characteristic.

Packet Structure

Each value update includes a 3-byte header:
BytesFieldDescription
0-1Packet NumberOverall packet counter (0-65535, wraps around)
2IndexPosition of this value within the current packet
Each audio packet contains 160 samples. If the packet exceeds (negotiated BLE MTU - 3 bytes), it will be split across multiple value notifications.Example: PCM 16-bit at 16 kHz
  • 160 samples × 2 bytes = 320 bytes per packet
  • On iOS devices, this typically results in:
    • Notification 1: packet n, index 0, 251 bytes
    • Notification 2: packet n+1, index 1, 75 bytes
All audio data is sent in little-endian format.

Implementation Example

# Example: Parsing audio packet header
def parse_audio_header(data: bytes):
    packet_number = int.from_bytes(data[0:2], 'little')
    index = data[2]
    audio_data = data[3:]
    return packet_number, index, audio_data