code: def datagram_received(self, data, addr):
          
          response = unpack_lifx_message(data)
          response.ip_addr = addr[0]
  
          mac_addr = response.target_addr
          if mac_addr == BROADCAST_MAC:
              return
  
          if type(response) == StateService and response.service == 1: # only look for UDP services
              # discovered
              remote_port = response.port
          elif type(response) == LightState:
              # looks like the lights are volunteering LigthState after booting
              remote_port = UDP_BROADCAST_PORT
          else:
              return
  
          if self.ipv6prefix:
              family = socket.AF_INET6
              remote_ip = mac_to_ipv6_linklocal(mac_addr, self.ipv6prefix)
          else:
              family = socket.AF_INET
              remote_ip = response.ip_addr
  
          if mac_addr in self.lights:
              # rediscovered
              light = self.lights[mac_addr]
  
              # nothing to do
              if light.registered:
                  return
  
              light.cleanup()
              light.ip_addr = remote_ip
              light.port = remote_port
          else:
              # newly discovered
              light = Light(self.loop, mac_addr, remote_ip, remote_port, parent=self)
              self.lights[mac_addr] = light
  
          coro = self.loop.create_datagram_endpoint(
              lambda: light, family=family, remote_addr=(remote_ip, remote_port))
  
          light.task = self.loop.create_task(coro)
docs: Method run when data is received from the devices
  
          This method will unpack the data according to the LIFX protocol.
          If a new device is found, the Light device will be created and started aa
          a DatagramProtocol and will be registered with the parent.
  
              :param data: raw data
              :type data: bytestring
              :param addr: sender IP address 2-tuple for IPv4, 4-tuple for IPv6
              :type addr: tuple