Пример #1
0
def sniffer(time):
    # Scan continuosly
    bt = BLE()
    bt.active(True)
    bt.irq(handler=bt_irq)
    print("Scanning for %dms..." % time, end="")
    bt.gap_scan(time, 10, 10)
    print("DONE!")
Пример #2
0
class ble:
    def __init__(self):
        debug("Initialising")
        self.bt = BLE()
        self.bt.irq(handler=self.bt_irq)
        print('waiting to set BLE active')
        self.bt.active(True)

        self.addresses = []
        for i in range(_ARRAYSIZE):
            self.addresses.append((100, b'AAAAAA', 'name'))
        self.conn_handle = 0
        self.connected = False
        self.write_flag = False
        self.read_flag = False
        self.notify = False
        self.index = 0
        self.scan = False
        self.notify_data = bytearray(30)
        self.address = bytearray(6)
        self.char_data = bytearray(30)
        self.temp = 0
        self.humidity = 0
        self.battery = 0
        self.voltage = 0

    def get_name(self, i):
        print('\r\n--------------------------------------------')
        print(self.type, prettify(self.address))
        if self.connect():
            sleep(1)
            if (self.read_data(0x0003)):
                try:
                    self.name = self.char_data.decode("utf-8")
                    self.name = self.name[:self.name.find(
                        '\x00')]  # drop trailing zeroes
                    print('self.name', self.name, ' length', len(self.name))
                except Exception as e:
                    debug('Error: Setup ' + str(e))

                print('Got', self.name)
            self.disconnect()

    def setup(self):
        # start device scan
        self.scan = False
        self.index = 0
        print('start scan')
        # Scan for 60s (at 100% duty cycle)
        try:
            self.bt.gap_scan(60000, 30000, 30000)
        except Exception as e:
            debug('Error: Scan ' + str(e))

        while not self.scan:
            pass

        # perform a scan to identify all the devices
        for i in range(len(self.addresses)):
            self.type, self.address, self.name = self.addresses[i]
            if self.type < 100:
                self.get_name(i)
                print('Name:', self.name)
                if self.name != 'name':
                    self.addresses[i] = (self.type, self.address, self.name)
                sleep(1)
            else:
                self.addresses = self.addresses[:i]  # truncate self.addresses
                break

    # Bluetooth Interrupt Handler
    def bt_irq(self, event, data):
        if event == _IRQ_SCAN_RESULT:
            # A single scan result.
            addr_type, addr, connectable, rssi, adv_data = data
            if addr_type == 0:
                print('address type = {}, address = {}'.format(
                    addr_type, prettify(addr)))
                if (addr_type, bytes(addr), 'name') not in self.addresses:
                    self.addresses[self.index] = (addr_type, bytes(addr),
                                                  'name')
                    self.index += 1

        elif event == _IRQ_SCAN_COMPLETE:
            # Scan duration finished or manually stopped.
            print('scan complete')
            self.scan = True

        elif event == _IRQ_PERIPHERAL_CONNECT:
            print('IRQ peripheral connect')
            self.conn_handle, _, _, = data
            self.connected = True

        if event == _IRQ_CENTRAL_CONNECT:
            # A central has self.connected to this peripheral.
            self.conn_handle, addr_type, addr = data
            print('A central has self.connected to this peripheral.',
                  self.conn_handle, addr_type, addr)

        elif event == _IRQ_CENTRAL_DISCONNECT:
            # A central has disself.connected from this peripheral.
            self.conn_handle, addr_type, addr = data
            print('A central has disself.connected from this peripheral.',
                  self.conn_handle, addr_type, addr)

        elif event == _IRQ_GATTS_WRITE:
            # A central has written to this characteristic or descriptor.
            self.conn_handle, attr_handle = data
            print(
                'A central has written to this characteristic or descriptor.',
                con_handle, attr_handle)

        elif event == _IRQ_GATTS_READ_REQUEST:
            # A central has issued a read. Note: this is a hard IRQ.
            # Return None to deny the read.
            # Note: This event is not supported on ESP32.
            self.conn_handle, attr_handle = data

        elif event == _IRQ_PERIPHERAL_DISCONNECT:
            # connected peripheral has disself.connected.
            self.conn_handle, addr_type, addr = data
            print('connected peripheral has disconnected.', self.conn_handle,
                  addr_type, prettify(addr))
            self.connected = False
            # print ('Set connect flag', self.connected)

        elif event == _IRQ_GATTC_SERVICE_RESULT:
            # Called for each service found by gattc_discover_services().
            self.conn_handle, start_handle, end_handle, uuid = data
            print(
                'Called for each service found by gattc_discover_services().',
                self.conn_handle, start_handle, end_handle, uuid)

        elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
            # Called for each characteristic found by gattc_discover_services().
            self.conn_handle, def_handle, value_handle, properties, uuid = data
            print(
                'Called for each characteristic found by gattc_discover_services().',
                self.conn_handle, def_handle, value_handle, properties, uuid)
            # print('Value handle {:02x}'.format(value_handle))
            # characteristics[self.index] = value_handle
            # self.index += 1

        elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
            # Called for each descriptor found by gattc_discover_descriptors().
            conn_handle, dsc_handle, uuid = data
            print(
                'Called for each descriptor found by gattc_discover_descriptors().',
                conn_handle, dsc_handle, uuid)

        elif event == _IRQ_GATTC_READ_RESULT:
            # A gattc_read() has completed.
            conn_handle, value_handle, char_data = data
            print('A gattc_read() has completed.', conn_handle, value_handle,
                  char_data)

            for b in range(len(char_data)):
                self.char_data[b] = char_data[b]

            self.read_flag = True

        elif event == _IRQ_GATTC_WRITE_STATUS:
            # A gattc_write() has completed.
            self.conn_handle, value_handle, status = data
            print('A gattc_write() has completed - status.', self.conn_handle,
                  value_handle, status)
            self.write_flag = True

        elif event == _IRQ_GATTC_NOTIFY:
            # A peripheral has sent a notify request.
            self.conn_handle, value_handle, notify_data = data
            print('A peripheral has sent a notify request.', self.conn_handle,
                  value_handle, notify_data)
            for b in range(len(notify_data)):
                self.notify_data[b] = notify_data[b]

            self.notify = True

        elif event == _IRQ_GATTC_INDICATE:
            # A peripheral has sent an indicate request.
            self.conn_handle, value_handle, self.notify_data = data
            print('A peripheral has sent an indicate request.',
                  self.conn_handle, value_handle, self.notify_data)

    def connect(self, type=0):
        # connect to the device at self.address
        count = 0
        while not self.connected:  # loop until connection successful
            print('Trying to connect to', prettify(self.address))
            try:
                conn = self.bt.gap_connect(type,
                                           self.address)  # try to connect
            except Exception as e:
                debug('Error: Connect ' + str(e))

            print('self.connected', self.connected)
            count += 1
            if count > 60: return False
            sleep(1)
        return True

    def read_data(self, value_handle):
        self.read_flag = False

        print('Reading Data')
        try:
            self.bt.gattc_read(self.conn_handle, value_handle)
        except Exception as e:
            debug('Error: Read ' + str(e))
            return False

        # returns false on timeout
        timer = 0
        while not self.read_flag:
            print('.', end='')
            print(self.read_flag)
            sleep(1)
            timer += 1
            if timer > 60:
                return False
        return True

    def disconnect(self):
        try:
            conn = self.bt.gap_disconnect(self.conn_handle)
        except Exception as e:
            debug('Error: Disconnect ' + str(e))

        # returns false on timeout
        timer = 0
        while self.connected:
            print('.', end='')
            sleep(1)
            timer += 1
            if timer > 60:
                return False
        return True

    def write_data(self, value_handle, data):
        self.write_flag = False

        # Checking for connection before write
        self.connect()
        try:
            self.bt.gattc_write(self.conn_handle, value_handle, data, 1)
        except Exception as e:
            debug('Error: Write ' + str(e))
            return False

        # returns false on timeout
        timer = 0
        while not self.write_flag:
            print('.', end='')
            sleep(1)
            timer += 1
            if timer > 60:
                return False
        return True

    def get_reading(self):
        self.connect()

        #enable notifications of Temperature, Humidity and Battery voltage
        data = b'\x01\x00'
        value_handle = 0x0038
        if (self.write_data(value_handle, data)):
            print('write ok')
        else:
            print('write failed')

        # enable energy saving
        data = b'\xf4\x01\x00'
        value_handle = 0x0046
        if (self.write_data(value_handle, data)):
            print('write ok')
        else:
            print('write failed')

        # wait for a notification
        self.notify = False
        timer = 0
        while not self.notify:
            print('.', end='')
            sleep(1)
            timer += 1
            if timer > 60:
                self.disconnect()
                return False

        print('Data received')
        self.temp = int.from_bytes(self.notify_data[0:2], 'little') / 100
        self.humidity = int.from_bytes(self.notify_data[2:3], 'little')
        self.voltage = int.from_bytes(self.notify_data[3:5], 'little') / 1000
        self.batteryLevel = min(int(round((self.voltage - 2.1), 2) * 100),
                                100)  #3.1 or above --> 100% 2.1 --> 0 %
        self.disconnect()
        return True
Пример #3
0
            ADV_DISSECTOR_MAP[advdtype](advpdu)
        except:
            print("\t%s" % (dumpHex(advpdu), ))

        i += advsize + 1


def bt_irq(event, data):
    if event == IRQ_SCAN_RESULT:
        # A single scan result.
        addr_type, addr, adv_type, rssi, adv_data = data
        if adv_type in ADV_TYPES:
            print(ADV_TYPES[adv_type])
            print("{addr: ", dumpHex(addr), ", addr_type: ", repr(addr_type),
                  ", rssi:", repr(rssi), "}")
            dumpAdvData(adv_data)
            print("\r\n")

    elif event == IRQ_SCAN_COMPLETE:
        # Scan duration finished or manually stopped.
        print('scan complete')


# Scan continuosly
bt = BLE()
bt.active(True)
bt.irq(handler=bt_irq)
print("Start scanning....", end="")
bt.gap_scan(0, 10, 10)
print("DONE!")
Пример #4
0
        conn_handle, attr_handle = data  # Don't know what conn_handle is, but attr_handle is the handle of the char written to

        print("GATTC write has occured: conn.", conn_handle, "on", attr_handle,
              ", new value:", bt.gatts_read(attr_handle))

        if (attr_handle == rdw) & (bt.gatts_read(rdw) == b"P"):  #\x50
            bt.gatts_write(rdw, b"\x00")
            radon_reading = random()
            print("Triggered radon readout. Writing {} to RDR.".format(
                radon_reading))
            bt.gatts_write(rdr, b"\x00\x00" + struct.pack('<f', radon_reading))


bt = BLE()
bt.active(True)
bt.irq(bt_irq)
#bt.gap_scan(2000, 30000, 30000)

SVC_UUID = UUID("00001523-1212-efde-1523-785feabcd123")  # Service UUID
RDW_UUID = UUID(
    "00001524-1212-efde-1523-785feabcd123"
)  # Notify/write characteristic UUID -> this is where the reader writes
RDR_UUID = UUID("00001525-1212-efde-1523-785feabcd123"
                )  # Radon readout characteristic UUID

# Assemble characteristics
RDW = (
    RDW_UUID,
    FLAG_WRITE,
)
RDR = (
Пример #5
0
class beacon_scanner:
    def __init__(self):
        a = 0
        while a <= 10:
            a = a + 1
            print("REINICIO\n")

        self.timer = Timer(0)
        self.timer.init(period=1200000,
                        mode=Timer.PERIODIC,
                        callback=handleInterrupt)  #Reset cada 20 mins
        self.wdt = WDT(
            timeout=100000
        )  #Watchdog configurado para que si no se alimenta en 100 seg realimente
        self.p13 = Pin(13, Pin.IN)  #Pin para interrumpir el main

        self.mac = ubinascii.hexlify(network.WLAN().config('mac'),
                                     ':').decode()
        print("Esto es la mac:", self.mac)

        # Scan for 10s (at 100% duty cycle)
        self.bt = BLE()

        self.lista_id = []
        self.lista_rssi = []

    def filtro(self, data):
        if "0201061aff4c000215" in data:  #Filtramos los dispositivos deseados a partir de su mac
            return True
        else:
            return False

    def adv_decode(self, adv_type, data):
        i = 0
        while i + 1 < len(data):
            if data[i + 1] == adv_type:
                return data[i + 2:i + data[i] + 1]
            i += 1 + data[i]
        return None

    def adv_decode_name(self, data):
        n = self.adv_decode(0x09, data)
        if n:
            return n.decode('utf-8')
        return data

    def do_connect(self):  #Funcion para conectarse al wifi
        wlan = network.WLAN(network.STA_IF)
        wlan.active(True)
        if not wlan.isconnected():
            print('connecting to network...')
            wlan.connect('Acciona Innovacion', 'Innovacion_IoT')
            while not wlan.isconnected():
                pass
        print('network config:', wlan.ifconfig())

    def bt_irq(self, event, data):

        #i=0
        if event == _IRQ_CENTRAL_CONNECT:
            # A central has connected to this peripheral.
            conn_handle, addr_type, addr = data
        elif event == _IRQ_CENTRAL_DISCONNECT:
            # A central has disconnected from this peripheral.
            conn_handle, addr_type, addr = data
        elif event == _IRQ_GATTS_WRITE:
            # A client has written to this characteristic or descriptor.
            conn_handle, attr_handle = data
        elif event == _IRQ_GATTS_READ_REQUEST:
            # A client has issued a read. Note: this is a hard IRQ.
            # Return None to deny the read.
            # Note: This event is not supported on ESP32.
            conn_handle, attr_handle = data
        elif event == _IRQ_SCAN_RESULT:  #Cuando escanea algo interrumpe aqui
            # A single scan result.
            addr_type, addr, adv_type, rssi, adv_data = data

            addr = ubinascii.hexlify(addr)
            adv_data = ubinascii.hexlify(adv_data)
            if self.filtro(adv_data) == True:
                #if filtro(addr) == True:  #Introducimos la mac para el filtro

                self.lista_id.append({"addr": addr, "rssi": rssi})

                #= urequests.post("https://innovacion-smartoffice.azurewebsites.net/snifferbluetooth/",

                #print(adv_data)
                #print("addr_type", "PUBLIC" if addr_type == 0 else "RANDOM",
                #    "addr", addr, "adv_type",adv_type,"rssi", rssi,
                #  "adv_data", adv_data )

                self.wdt.feed()

        elif event == _IRQ_SCAN_DONE:
            # Scan duration finished or manually stopped.
            import gc
            import micropython
            gc.collect()
            micropython.mem_info()
            print('-----------------------------')
            print('Initial free: {} allocated: {}'.format(
                gc.mem_free(), gc.mem_alloc()))
            pass
        elif event == _IRQ_PERIPHERAL_CONNECT:
            # A successful gap_connect().
            conn_handle, addr_type, addr = data
        elif event == _IRQ_PERIPHERAL_DISCONNECT:
            # Connected peripheral has disconnected.
            conn_handle, addr_type, addr = data
        elif event == _IRQ_GATTC_SERVICE_RESULT:
            # Called for each service found by gattc_discover_services().
            conn_handle, start_handle, end_handle, uuid = data
        elif event == _IRQ_GATTC_SERVICE_DONE:
            # Called once service discovery is complete.
            # Note: Status will be zero on success, implementation-specific value otherwise.
            conn_handle, status = data
        elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
            # Called for each characteristic found by gattc_discover_services().
            conn_handle, def_handle, value_handle, properties, uuid = data
        elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
            # Called once service discovery is complete.
            # Note: Status will be zero on success, implementation-specific value otherwise.
            conn_handle, status = data
        elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
            # Called for each descriptor found by gattc_discover_descriptors().
            conn_handle, dsc_handle, uuid = data
        elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
            # Called once service discovery is complete.
            # Note: Status will be zero on success, implementation-specific value otherwise.
            conn_handle, status = data
        elif event == _IRQ_GATTC_READ_RESULT:
            # A gattc_read() has completed.
            conn_handle, value_handle, char_data = data
        elif event == _IRQ_GATTC_READ_DONE:
            # A gattc_read() has completed.
            # Note: The value_handle will be zero on btstack (but present on NimBLE).
            # Note: Status will be zero on success, implementation-specific value otherwise.
            conn_handle, value_handle, status = data
        elif event == _IRQ_GATTC_WRITE_DONE:
            # A gattc_write() has completed.
            # Note: The value_handle will be zero on btstack (but present on NimBLE).
            # Note: Status will be zero on success, implementation-specific value otherwise.
            conn_handle, value_handle, status = data
        elif event == _IRQ_GATTC_NOTIFY:
            # A server has sent a notify request.
            conn_handle, value_handle, notify_data = data
        elif event == _IRQ_GATTC_INDICATE:
            # A server has sent an indicate request.
            conn_handle, value_handle, notify_data = data
        elif event == _IRQ_GATTS_INDICATE_DONE:
            # A client has acknowledged the indication.
            # Note: Status will be zero on successful acknowledgment, implementation-specific value otherwise.
            conn_handle, value_handle, status = data
        elif event == _IRQ_MTU_EXCHANGED:
            # MTU exchange complete (either initiated by us or the remote device).
            conn_handle, mtu = data

    def run(self):
        #self.do_connect()

        self.bt.active(True)
        self.bt.irq(handler=self.bt_irq)
        while self.p13.value() != 1:
            self.bt.gap_scan(
                1000, 30000, 30000
            )  #Escaneo total 1000 ms, cada 30000 us escanea, y escanea durante 30000 us
            time.sleep(5)
            ota_updater = OTAUpdater('https://github.com/AliasJavier/ble_code')
            current_version = ota_updater.version()

            if len(self.lista_id) >= 1:
                url = "http://innovacion-smartoffice.azurewebsites.net/snifferbluetooth/"
                data = self.mac + '\n'
                data = data + str(current_version) + '\n'
                for elemento in self.lista_id:
                    data = data + elemento['addr'].decode(
                        "utf-8") + ","  #Lo ponemos en el formato deseado
                    data = data + str(elemento['rssi']) + "\n"

                print(data)
                header_data = {"content-type": 'text/plain'}
                try:  #Comprueba si puede enviar por wifi
                    r = requests.post(url, data=data, headers=header_data)
                    results = r.text
                    print(results)
                    self.lista_id = []
                except:  #En caso de no estar conectado lo forzamos a reconectarse
                    self.do_connect()
Пример #6
0
class Ble:
    def __init__(self):
        logging.info("Initializing BLE...")
        self.bt = BLE()
        self.bt.irq(handler=self.bt_irq)
        logging.info('Waiting to set BLE active...')
        self.bt.active(True)

        self.addresses = []
        for i in range (_ARRAYSIZE):
            self.addresses.append((-1, -1, b'AAAAAA', DEVICE_NAME_PLACEHOLDER, 0))
        self.device_index = 0
        self.type = 0
        self.address = bytearray(6)
        self.name = 0
        self.last_read = 0
        self.conn_handle = 0
        self.connected = False
        self.read_flag = False
        self.write_flag = False
        self.write_status = -1
        self.notify_flag = False
        self.scan_complete = False
        self.notify_data = bytearray(30)
        self.char_data = bytearray(30)
        self.temperature = 0
        self.humidity = 0
        self.battery_voltage = 0
        self.battery_level = 0


    def setup(self, scan_for_devices=True, devices_list=[]):
        self.device_index = 0

        # Load devices list (if not empty)
        if devices_list:
            logging.info('Loading device list...')
            for (mac_address, device_name) in devices_list:
                self.addresses[self.device_index] = (self.device_index, 0, utils.encode_mac(mac_address), device_name, 0)
                self.device_index += 1

        if scan_for_devices:
            # Start device scan
            self.scan_devices()

        # Perform a scan to identify all the devices
        self.identify_devices()


    def scan_devices(self):
        self.scan_complete = False
        logging.info('Starting scan...')
        # Run a scan operation lasting for the specified duration (in milliseconds).
        # Use interval_us and window_us to optionally configure the duty cycle.
        # The scanner will run for window_us microseconds every interval_us microseconds for a total of duration_ms milliseconds.
        # The default interval and window are 1.28 seconds and 11.25 milliseconds respectively (background scanning).
        #
        # Scan for 60s (at 100% duty cycle)
        duration_ms = 60000 # milliseconds
        interval_us = 30000 # microseconds
        window_us   = 30000 # microseconds
        try:
            self.bt.gap_scan(duration_ms, interval_us, window_us)
        except Exception as e:
            utils.log_error_to_file('ERROR: scan - ' + str(e))
            
        while not self.scan_complete:
            pass


    def identify_devices(self):
        logging.info('Starting identify...')
        for i in range(len(self.addresses)):
            self.device_index, self.type, self.address, self.name, self.last_read = self.addresses[i]
            if self.type >= 0:
                if self.name == DEVICE_NAME_PLACEHOLDER:
                    self.get_name(i)
                    logging.debug('Name: {}', self.name)
                    if self.name != DEVICE_NAME_PLACEHOLDER:
                        self.addresses[i] = (self.device_index, self.type, self.address, self.name, self.last_read)
                    time.sleep(1)
            else:
                self.addresses = self.addresses[:i]            # truncate self.addresses
                break


    def get_name(self, i):
        print('--------------------------------------------------')
        logging.debug('Type: {} - Address: {}', self.type, utils.decode_mac(self.address))
        if self.connect():
            time.sleep(1)
            if self.read_data(0x0003):
                try:
                    self.name = self.char_data.decode("utf-8")
                    self.name = self.name[:self.name.find('\x00')]  # drop trailing zeroes
                    logging.debug('Name: {} - Length: {}', self.name, len(self.name))
                except Exception as e:
                    utils.log_error_to_file('ERROR: setup ' + utils.decode_mac(self.address) + ' - ' + str(e))

            self.disconnect()


    def connect(self, mswait=2000, type=0):
        # Connect to the device at self.address
        count = 0
        while not self.connected and count < 60000:
            logging.info('Trying to connect to {}...', utils.decode_mac(self.address))
            try:
                self.bt.gap_connect(type, self.address)
            except Exception as e:
                utils.log_error_to_file('ERROR: connect to ' + utils.decode_mac(self.address) + ' - ' + str(e))
            now = time.ticks_ms()
            while time.ticks_diff(time.ticks_ms(), now) < mswait:
                if self.connected:
                    break
            count += mswait
        return self.connected


    def disconnect(self):
        logging.info('Disconnecting...')
        try:
            conn = self.bt.gap_disconnect(self.conn_handle)
        except Exception as e:
            utils.log_error_to_file('ERROR: disconnect from ' + utils.decode_mac(self.address) + ' - ' + str(e))

        # Returns false on timeout
        timer = 0
        while self.connected:
            # print('.', end='')
            time.sleep(1)
            timer += 1
            if timer > 60:
                return False
        return True


    def read_data(self, value_handle):
        self.read_flag = False

        logging.info('Reading data...')
        try:
            self.bt.gattc_read(self.conn_handle, value_handle)
        except Exception as e:
            utils.log_error_to_file('ERROR: read from ' + utils.decode_mac(self.address) + ' - ' + str(e))
            return False

        # Returns false on timeout
        timer = 0
        while not self.read_flag:
            # print('.', end='')
            time.sleep(1)
            timer += 1
            if timer > 60:
                return False
        return True


    def write_data(self, value_handle, data):
        self.write_flag = False
        self.write_status = -1

        # Checking for connection before write
        self.connect()
        logging.debug('Writing data...')
        try:
            self.bt.gattc_write(self.conn_handle, value_handle, data, 1)
        except Exception as e:
            utils.log_error_to_file('ERROR: write to ' + utils.decode_mac(self.address) + ' - ' + str(e))
            return False

        # Returns false on timeout
        timer = 0
        while not self.write_flag:
            # print('.', end='')
            time.sleep(1)
            timer += 1
            if timer > 60:
                return False
        return self.write_status == 0


    def get_reading(self):
        self.connect()

        # Enable notifications of Temperature, Humidity and Battery voltage
        logging.info('Enabling notifications for data readings...')
        self.notify_flag = False
        data = b'\x01\x00'
        value_handle = 0x0038
        retry = 1
        while not self.write_data(value_handle, data):
            logging.warning('Write failed ({}/3)', retry)
            if retry < 3:
                retry += 1
            else:
                self.disconnect()
                return False
        logging.debug('Write successful')

        # Enable energy saving
        logging.info('Enabling energy saving...')
        data = b'\xf4\x01\x00'
        value_handle = 0x0046
        if self.write_data(value_handle, data):
            logging.debug('Write successful')
        else:
            logging.warning('Write failed')

        # Wait for a notification
        logging.info('Waiting for a notification...')
        timer = 0
        while not self.notify_flag:
            # print('.', end='')
            time.sleep(1)
            timer += 1
            if timer > 60:
                self.disconnect()
                return False

        logging.info('Data received!')
        self.temperature = int.from_bytes(self.notify_data[0:2], 'little') / 100
        self.humidity = int.from_bytes(self.notify_data[2:3], 'little')
        self.battery_voltage = int.from_bytes(self.notify_data[3:5], 'little') / 1000
        self.battery_level = min(int(round((self.battery_voltage - 2.1), 2) * 100), 100) # 3.1 or above --> 100% 2.1 --> 0 %
        self.disconnect()

        self.last_read = time.time()
        self.addresses[self.device_index] = (self.device_index, self.type, self.address, self.name, self.last_read)
        return True


    def address_already_present(self, address_to_check):
        for (device_index, type, address, name, last_read) in self.addresses:
            if address == address_to_check:
                return True
        return False


    # Bluetooth Interrupt Handler
    def bt_irq(self, event, data):
        if event == _IRQ_SCAN_RESULT:
            # A single scan result.
            addr_type, addr, connectable, rssi, adv_data = data
            if addr_type == 0:
                logging.debug('Address type: {} - Address: {}', addr_type, utils.decode_mac(addr))
                if not self.address_already_present(bytes(addr)):
                    self.addresses[self.device_index] = (self.device_index, addr_type, bytes(addr), DEVICE_NAME_PLACEHOLDER, 0)
                    self.device_index += 1
                
        elif event == _IRQ_SCAN_COMPLETE:
            # Scan duration finished or manually stopped.
            logging.info('Scan complete')
            self.scan_complete = True
            
        elif event == _IRQ_PERIPHERAL_CONNECT:
            logging.debug('Peripheral connected.')
            self.conn_handle, _, _, = data
            self.connected = True
            
        if event == _IRQ_CENTRAL_CONNECT:
            # A central has connected to this peripheral.
            self.conn_handle, addr_type, addr = data
            logging.debug('A central has connected to this peripheral.')
            logging.debug('Connection handle: {} - Address type: {} - Address: {}', self.conn_handle, addr_type, addr)

        elif event == _IRQ_CENTRAL_DISCONNECT:
            # A central has disconnected from this peripheral.
            self.conn_handle, addr_type, addr = data
            logging.debug('A central has disconnected from this peripheral.')
            logging.debug('Connection handle: {} - Address type: {} - Address: {}', self.conn_handle, addr_type, addr)

        elif event == _IRQ_GATTS_WRITE:
            # A central has written to this characteristic or descriptor.
            self.conn_handle, attr_handle = data
            logging.debug('A central has written to this characteristic or descriptor.')
            logging.debug('Connection handle: {} - Attribute handle: {}', self.conn_handle, attr_handle)

        elif event == _IRQ_GATTS_READ_REQUEST:
            # A central has issued a read. Note: this is a hard IRQ.
            # Return None to deny the read.
            # Note: This event is not supported on ESP32.
            self.conn_handle, attr_handle = data
            
        elif event == _IRQ_PERIPHERAL_DISCONNECT:
            # Connected peripheral has disconnected.
            self.conn_handle, addr_type, addr = data
            logging.debug('Peripheral disconnected.')
            logging.debug('Connection handle: {} - Address type: {} - Address: {}', self.conn_handle, addr_type, utils.decode_mac(addr))
            self.connected = False
            # print('Set connect flag', self.connected)
            
        elif event == _IRQ_GATTC_SERVICE_RESULT:
            # Called for each service found by gattc_discover_services().
            self.conn_handle, start_handle, end_handle, uuid = data
            logging.debug('Called for each service found by gattc_discover_services().')
            logging.debug('Connection handle: {} - Start handle: {} - End handle: {} - UUID: {}', self.conn_handle, start_handle, end_handle, uuid)

        elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
            # Called for each characteristic found by gattc_discover_services().
            self.conn_handle, def_handle, value_handle, properties, uuid = data
            logging.debug('Called for each characteristic found by gattc_discover_services().')
            logging.debug('Connection handle: {} - Def handle: {} - Value handle: {} - Properties: {} - UUID: {}', self.conn_handle, def_handle, value_handle, properties, uuid)
            # print('Value handle {:02x}'.format(value_handle))
            # characteristics[self.index] = value_handle
            # self.index += 1
            
        elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
            # Called for each descriptor found by gattc_discover_descriptors().
            conn_handle, dsc_handle, uuid = data
            logging.debug('Called for each descriptor found by gattc_discover_descriptors().')
            logging.debug('Connection handle: {} - Dsc handle: {} - UUID: {}', conn_handle, dsc_handle, uuid)

        elif event == _IRQ_GATTC_READ_RESULT:
            # A gattc_read() has completed.
            conn_handle, value_handle, char_data = data
            logging.debug('A gattc_read() has completed.')
            logging.debug('Connection handle: {} - Value handle: {} - Char data: {}', conn_handle, value_handle, char_data)

            for b in range(len(char_data)):
                self.char_data[b] = char_data[b]
                
            self.read_flag = True

        elif event == _IRQ_GATTC_WRITE_STATUS:
            # A gattc_write() has completed.
            self.conn_handle, value_handle, status = data
            logging.debug('A gattc_write() has completed - status.')
            logging.debug('Connection handle: {} - Value handle: {} - Status: {}', self.conn_handle, value_handle, status)
            self.write_flag = True
            self.write_status = status
            
        elif event == _IRQ_GATTC_NOTIFY:
            # A peripheral has sent a notify request.
            self.conn_handle, value_handle, notify_data = data
            logging.debug('A peripheral has sent a notify request.')
            logging.debug('Connection handle: {} - Value handle: {} - Notify data: {}', self.conn_handle, value_handle, notify_data)
            for b in range(len(notify_data)):
                self.notify_data[b] = notify_data[b]
            
            self.notify_flag = True
            
        elif event == _IRQ_GATTC_INDICATE:
            # A peripheral has sent an indicate request.
            self.conn_handle, value_handle, self.notify_data = data
            logging.debug('A peripheral has sent an indicate request.')
            logging.debug('Connection handle: {} - Value handle: {} - Notify data: {}', self.conn_handle, value_handle, self.notify_data)