## RaydonEye uses BLE LED Button Service (LBS) UUID 00001523-1212-EFDE-1523-785FEABCD123
## [!] ble only supports a single connection, if RadonEye App is running this will fail

import BLE_GATT
import time
from gi.repository import GLib
import struct
import subprocess

dev = None

# [!] To get this to work bluetoothctl needs to connect to the device before using BLE_GATT.connect
def ble_ctl(addr:str):
    """
    use bluetoothctl interactively: scan on, ... wait ..., scan off, connect CF:CD:27:79:55:6B, exit
    subprocess has a relevant bug in line-buffering, see issue 21471
    """
    ctl = subprocess.Popen(['bluetoothctl'], stdin = subprocess.PIPE)
    def writeHelper(proc, str, delay = 1):
        proc.stdin.write(str.encode('utf-8'))
        proc.stdin.flush()
        time.sleep(delay)
    # send bluetoothctl commands interactively
    writeHelper(ctl, "scan on\n", 4)
    writeHelper(ctl, "scan off\n")
    writeHelper(ctl, "connect " + addr + "\n", 3)
    writeHelper(ctl, "exit\n")
    # wait for child subprocess to terminate
    while True:
        if None != ctl.poll():
            break
        time.sleep(.1)

def radonEye_toFloat(res):
    """
    pulls a IEEE754 float representing the most recent radon sample in picocuries per
    liter from the LBS Read Characteristic, the sample is updated 30 times an hour

    RadonEye stores in 4 bytes, big-endian starting at offset 3 of LBS "response"
    """
    return struct.unpack('<f', bytes(res[2:6]))


# LED Button Service - Write 00001524-1212-EFDE-1523-785FEABCD123
def push_button():
    print("timeout, pushing LBS button")
    dev.char_write('00001524-1212-EFDE-1523-785FEABCD123', b'\x50')
    return True

def notify_handler(value):
    print(" ".join(hex(x) for x in value))
    print(radonEye_toFloat(value), " picocuries per liter")

while True:
    radonEyeMac = 'CF:CD:27:79:55:6B'
    try:
        # Use Central Role BlueZ D-Bus API (BLE-GATT) to connect to peripheral (RadonEye)
        dev = BLE_GATT.Central(radonEyeMac)
        break
    except:
        print("device not found, retrying...\n")
        # using OS time take a break for a tenth of a second, then try bluetoothctl commands
        time.sleep(.1)
        ble_ctl(radonEyeMac)
        continue

# Open connection, do not disconnect, BLE only supports a single open connection
dev.connect()

# LED Button Service - Notify/Read 00001525-1212-EFDE-1523-785FEABCD123
dev.on_value_change('00001525-1212-EFDE-1523-785FEABCD123', notify_handler)
GLib.timeout_add_seconds(12, push_button)
dev.wait_for_notifications()
