Skip to content

Conversation

dipakgmx
Copy link
Member

@dipakgmx dipakgmx commented Oct 12, 2025

This pull request adds support for the Bluetooth Elapsed Time Service (ETS) to Zephyr.

The setup can be tested via this bleak script:

import asyncio
import datetime
import time

from bleak import BleakScanner, BleakClient

ETS_SERVICE_UUID = "0000183f-0000-1000-8000-00805f9b34fb"
ETS_CURRENT_ELAPSED_TIME_UUID = "00002bf2-0000-1000-8000-00805f9b34fb"

FLAGS = 0x3A  # UTC + TZ/DST + current timeline + 1 ms resolution
TIME_SYNC_SRC = 0x02  # 0x01=manual, 0x02=network

async def find_first_ets_device():
    print("Scanning for ETS service advertisements...")
    devices = await BleakScanner.discover(service_uuids=[ETS_SERVICE_UUID], timeout=5.0)
    if not devices:
        raise RuntimeError("No device advertising the ETS service was found")
    dev = devices[0]
    print(f"Found ETS peripheral: {dev.name or '(no name)'} [{dev.address}]")
    return dev


def build_payload_now_utc() -> bytes:
    # elapsed ms since 2000-01-01 UTC
    ets_ms = int(
        (datetime.datetime.now(datetime.timezone.utc)
         - datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)
         ).total_seconds() * 1000
    )

    # timezone offset in 15-minute units (for info only)
    standard_offset_minutes = -time.timezone // 60
    dst_offset_minutes = (-time.altzone // 60) - standard_offset_minutes if time.daylight else 0
    tz_dst_offset_minutes = (standard_offset_minutes + dst_offset_minutes) // 15

    b = bytearray()
    b.append(FLAGS)
    b += ets_ms.to_bytes(6, "little")  # 48-bit value
    b.append(TIME_SYNC_SRC & 0xFF)
    b.append(tz_dst_offset_minutes & 0xFF)
    return bytes(b)


def decode_ets_payload(data: bytes):
    if len(data) < 9:
        print(f"Unexpected length {len(data)}")
        return
    time_value = int.from_bytes(data[1:7], "little")
    tz_dst = int.from_bytes(data[8:9], "little", signed=True)
    unix_time = datetime.datetime(2000, 1, 1, tzinfo=datetime.UTC) + datetime.timedelta(
        milliseconds=time_value)
    print(f"Time is {unix_time.isoformat()} (offset {tz_dst * 15} min)")


async def main():
    dev = await find_first_ets_device()
    async with BleakClient(dev) as client:
        payload = build_payload_now_utc()
        await client.write_gatt_char(ETS_CURRENT_ELAPSED_TIME_UUID, payload, response=True)
        print("Wrote ETS now:", payload.hex(" "))
        data = await client.read_gatt_char(ETS_CURRENT_ELAPSED_TIME_UUID)
        decode_ets_payload(data)

if __name__ == "__main__":
    asyncio.run(main())

@dipakgmx dipakgmx force-pushed the feat/bt-ets branch 2 times, most recently from 4543b80 to 486abe5 Compare October 12, 2025 13:30
Added UUID for Elapsed Time Service (0x183F).

Signed-off-by: Dipak Shetty <[email protected]>
@dipakgmx dipakgmx force-pushed the feat/bt-ets branch 4 times, most recently from eebf628 to c49316c Compare October 12, 2025 14:50
Added support for elapsed time service (ETS).

Signed-off-by: Dipak Shetty <[email protected]>
Added elapsed time service (ETS) GATT service sample.
The sample allows the user to set the system realtime clock
on the board and read the time.

Signed-off-by: Dipak Shetty <[email protected]>
Copy link

@dipakgmx dipakgmx marked this pull request as ready for review October 12, 2025 15:58
@zephyrbot zephyrbot added area: Samples Samples area: Bluetooth Host Bluetooth Host (excluding BR/EDR) area: Bluetooth labels Oct 12, 2025
@Thalley Thalley removed their request for review October 12, 2025 18:49
@cvinayak cvinayak removed their request for review October 15, 2025 04:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Bluetooth Host Bluetooth Host (excluding BR/EDR) area: Bluetooth area: Samples Samples

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants