Sends a tunneling request based on the given CEMI data.

        This method does not wait for an acknowledge or result frame.

def send_tunnelling_request(self, cemi, auto_connect=True):
        """Sends a tunneling request based on the given CEMI data.

        This method does not wait for an acknowledge or result frame.
        """
        if not self.connected:
            if auto_connect:
                if not self.connect():
                    raise KNXException("KNX tunnel not reconnected")
            else:
                raise KNXException("KNX tunnel not connected")

        frame = KNXIPFrame(KNXIPFrame.TUNNELING_REQUEST)
        # Connection header see KNXnet/IP 4.4.6 TUNNELLING_REQUEST
        body = [0x04, self.channel, self.seq, 0x00]
        if self.seq < 0xff:
            self.seq += 1
        else:
            self.seq = 0
        body.extend(cemi.to_body())
        frame.body = body
        self.data_server.socket.sendto(
            frame.to_frame(), (self.remote_ip, self.remote_port))

        # See KNX specification 3.8.4 chapter 2.6 "Frame confirmation"
        # Send KNX packet 2 times if not acknowledged and close
        # the connection if no ack is received
        res = self.ack_semaphore.acquire(blocking=True, timeout=1)
        # Resend package if not acknowledged after 1 seconds
        if not res:
            self.data_server.socket.sendto(
                frame.to_frame(), (self.remote_ip, self.remote_port))

            res = self.ack_semaphore.acquire(blocking=True, timeout=1)

        # disconnect and reconnect of not acknowledged
        if not res:
            self.disconnect()
            self.connect()

        return res