import bluetooth, time, struct

ble = bluetooth.BLE()
ble.active(True)
conn = None
notify_data = []
write_done_ev = False

def irq(ev, data):
    global conn, write_done_ev
    if ev == 7:
        c, at, addr = data; conn = c; print("CONN", conn)
    elif ev == 8:
        conn = None; print("DISC")
    elif ev == 17:
        write_done_ev = True; print("WR_DONE", tuple(data))
    elif ev == 18:
        ch, vh, d = data
        nd = bytes(d)
        notify_data.append((vh, nd))
        print("NOTIFY vh={} {}b: {}".format(vh, len(nd), nd.hex()))
    else:
        pass  # quiet

ble.irq(irq)
ble.gap_connect(0, bytes([0x24,0x19,0x72,0x61,0x9D,0x62]))
t = time.ticks_ms()
while conn is None:
    if time.ticks_diff(time.ticks_ms(), t) > 10000: raise Exception("NO CONN")
    time.sleep_ms(50)
time.sleep_ms(600)

def wait_wd(ms=4000):
    global write_done_ev
    write_done_ev = False
    t = time.ticks_ms()
    while not write_done_ev:
        if time.ticks_diff(time.ticks_ms(), t) > ms: return False
        time.sleep_ms(30)
    return True

# CCCDs: val_h=20 -> CCCD=21, val_h=23 -> CCCD=24
ble.gattc_write(conn, 21, struct.pack("<H",0x0001), 1); wait_wd(); print("CCCD1")
ble.gattc_write(conn, 24, struct.pack("<H",0x0001), 1); wait_wd(); print("CCCD2")
time.sleep_ms(500)

def crc16(data):
    crc = 0xFFFF
    for b in data:
        crc ^= b
        for _ in range(8):
            crc = (crc>>1)^0xA001 if crc&1 else crc>>1
    return crc & 0xFFFF

SN = b"30000251257777051"
payload = b"\x0a" + bytes([len(SN)]) + SN
frame = b"HM\xa3\x03" + struct.pack(">HHH", 1, crc16(payload), len(payload)+10) + payload
print("TX:", frame.hex())

# Try write-with-response first
ble.gattc_write(conn, 18, frame, 1); r = wait_wd(6000)
print("WR resp:", r)

t = time.ticks_ms()
while len(notify_data) == 0:
    if time.ticks_diff(time.ticks_ms(), t) > 12000: print("NO NOTIFY"); break
    time.sleep_ms(100)

if not notify_data:
    # Try write-without-response
    print("Retrying with mode=0...")
    notify_data.clear()
    ble.gattc_write(conn, 18, frame, 0)
    t = time.ticks_ms()
    while len(notify_data) == 0:
        if time.ticks_diff(time.ticks_ms(), t) > 12000: print("STILL NO NOTIFY"); break
        time.sleep_ms(100)

print("Done. Got", len(notify_data), "notifies")
for vh, d in notify_data: print("vh={} {}".format(vh, d.hex()))
if conn: ble.gap_disconnect(conn)
