docs: def get_async_blackbird(port_url, loop):
      """
      Return asynchronous version of Blackbird interface
      :param port_url: serial port, i.e. '/dev/ttyUSB0'
      :return: asynchronous implementation of Blackbird interface
      """
  
      lock = asyncio.Lock()
  
      def locked_coro(coro):
          @asyncio.coroutine
          @wraps(coro)
          def wrapper(*args, **kwargs):
              with (yield from lock):
                  return (yield from coro(*args, **kwargs))
          return wrapper
  
      class BlackbirdAsync(Blackbird):
          def __init__(self, blackbird_protocol):
              self._protocol = blackbird_protocol
  
          @locked_coro
          @asyncio.coroutine
          def zone_status(self, zone: int):
              string = yield from self._protocol.send(_format_zone_status_request(zone), skip=15)
              return ZoneStatus.from_string(zone, string)
  
          @locked_coro
          @asyncio.coroutine
          def set_zone_power(self, zone: int, power: bool):
              yield from self._protocol.send(_format_set_zone_power(zone, power))
  
          @locked_coro
          @asyncio.coroutine
          def set_zone_source(self, zone: int, source: int):
              yield from self._protocol.send(_format_set_zone_source(zone, source))
  
          @locked_coro
          @asyncio.coroutine
          def set_all_zone_source(self, source: int):
              yield from self._protocol.send(_format_set_all_zone_source(source))
  
          @locked_coro
          @asyncio.coroutine
          def lock_front_buttons(self):
              yield from self._protocol.send(_format_lock_front_buttons())
  
          @locked_coro
          @asyncio.coroutine
          def unlock_front_buttons(self):
              yield from self._protocol.send(_format_unlock_front_buttons())
  
          @locked_coro
          @asyncio.coroutine
          def lock_status(self):
              string = yield from self._protocol.send(_format_lock_status())
              return LockStatus.from_string(string)
  
      class BlackbirdProtocol(asyncio.Protocol):
          def __init__(self, loop):
              super().__init__()
              self._loop = loop
              self._lock = asyncio.Lock()
              self._transport = None
              self._connected = asyncio.Event(loop=loop)
              self.q = asyncio.Queue(loop=loop)
  
          def connection_made(self, transport):
              self._transport = transport
              self._connected.set()
              _LOGGER.debug('port opened %s', self._transport)
  
          def data_received(self, data):
              asyncio.ensure_future(self.q.put(data), loop=self._loop)
  
          @asyncio.coroutine
          def send(self, request: bytes, skip=0):
              yield from self._connected.wait()
              result = bytearray()
              # Only one transaction at a time
              with (yield from self._lock):
                  self._transport.serial.reset_output_buffer()
                  self._transport.serial.reset_input_buffer()
                  while not self.q.empty():
                      self.q.get_nowait()
                  self._transport.write(request)
                  try:
                      while True:
                          result += yield from asyncio.wait_for(self.q.get(), TIMEOUT, loop=self._loop)
                          if len(result) > skip and result[-LEN_EOL:] == EOL:
                              ret = bytes(result)
                              _LOGGER.debug('Received "%s"', ret)
                              return ret.decode('ascii')
                  except asyncio.TimeoutError:
                      _LOGGER.error("Timeout during receiving response for command '%s', received='%s'", request, result)
                      raise
  
      _, protocol = yield from create_serial_connection(loop, functools.partial(BlackbirdProtocol, loop), port_url, baudrate=9600)
  
      return BlackbirdAsync(protocol)