Ok, so after yesterday I realized that the command I was looking at was executed in a loop, but didn't "start" the heart rate. I looked for other instances of running "commands" over bluetooth with `executeReqCmd` and there's a `StartHeartRateReq` that's... probably starting the heart rate monitoring. `StartHeartRateReq.getSimpleReq((byte) 1), aCallBack` Which calls `new StartHeartRateReq(b, b < 3 ? (byte) 0 : BLEDataFormatUtils.decimalToBCD(25));` Or `new StartHeartRateReq(1, 0);` This packet looks to have type `105` from the `public static final byte CMD_START_HEART_RATE = 105;` and "sub data" is `[0x01, 0x00]` Writing that packet and the `CMD_REAL_TIME_HEART_RATE` from yesterday lit up the green LED! And there's 2 response packets that get returned that are just `i` and `j`... but still, it's something! ```python import asyncio from bleak import BleakScanner, BleakClient from bleak.backends.characteristic import BleakGATTCharacteristic ADDRESS = "70:CB:0D:D0:34:1C" MODEL_NBR_UUID = "2A24" UART_SERVICE_UUID = "6E40FFF0-B5A3-F393-E0A9-E50E24DCCA9E" UART_RX_CHAR_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" UART_TX_CHAR_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" CMD_REAL_TIME_HEART_RATE = 30 CMD_START_HEART_RATE = 105; def make_packet(command_key: int, sub_data: bytearray) -> bytearray: packet = bytearray(15) packet[0] = command_key assert len(sub_data) <= 14 packet[1:len(sub_data)] = sub_data packet[-1] = crc(packet) return packet def crc(packet: bytearray) -> int: return sum(packet) & 255 async def main(): print("connecting") def handle_rx(_: BleakGATTCharacteristic, data: bytearray): print("received:", data) async with BleakClient(ADDRESS) as client: print("Connected") await client.start_notify(UART_TX_CHAR_UUID, handle_rx) nus = client.services.get_service(UART_SERVICE_UUID) rx_char = nus.get_characteristic(UART_RX_CHAR_UUID) packet = make_packet(CMD_START_HEART_RATE, bytearray(b'\x00\x01')) await client.write_gatt_char(rx_char, packet, response=False) print("wrote packet, waiting...") await asyncio.sleep(2) packet = make_packet(CMD_REAL_TIME_HEART_RATE, bytearray(b'3')) await client.write_gatt_char(rx_char, packet, response=False) await asyncio.sleep(20) if __name__ == '__main__': asyncio.run(main()) ``` The decompiled source code is now up at https://github.com/tahnok/QRing_decompiled The python code will live at https://github.com/tahnok/ATC_RF03_Ring/tree/python_client for a while before I put up a PR