func DiscoverDevices(listentime time.Duration, listenUDPPort int) (devlist []Device, err error) {
	if listentime <= 0 {
		err = fmt.Errorf("a positive listentime duration must be given")
		return
	}
	ipv4s, err := ipV4Addrs()
	if err != nil {
		return
	}
	ch := make(chan []Device)
	devlist = make([]Device, 0)
	var wg, wgdone sync.WaitGroup
	wgdone.Add(1)
	go func() {
		defer wgdone.Done()
		for {
			d, ok := <-ch
			if !ok {
				return
			}
			devlist = append(devlist, d...)
		}
	}()
	for _, a := range ipv4s {
		wg.Add(1)
		go func(ip net.IP) {
			defer wg.Done()
			laddr := &net.UDPAddr{IP: ip, Port: listenUDPPort}
			found, e := DiscoverDevicesFromAddr(listentime, laddr)
			if e != nil {
				err = e
				return
			}
			ch <- found
		}(a)
	}
	wg.Wait()
	close(ch)
	wgdone.Wait()
	return
}
Try to discover all reachable BroadLink devices.
The function waits listentime for reply from devices.
listenport is a UDP port number to be listened on. If listenport is zero, a port number will be chosen automatically. Be sure the port is not blocked by firewalls.
package broadlink
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"sync"
	"time"
)
type WifiSecurity int
const (
	WIFI_SECURITY_NONE WifiSecurity = iota
	WIFI_SECURITY_WEP
	WIFI_SECURITY_WPA1
	WIFI_SECURITY_WPA2
	WIFI_SECURITY_WPA_CCMP  
	WIFI_SECURITY_5_UNKNOWN
	WIFI_SECURITY_WPA_TKIP  
)
var (
	BroadLinkDevicePort = 80
)
func DiscoverDevicesFromAddr(listentime time.Duration, localaddr *net.UDPAddr) (devlist []Device, err error) {
	if localaddr == nil {
		err = fmt.Errorf("localaddr cannot be nil")
		return
	}
	deadline := time.Now().Add(listentime)
	udpconn, err := net.ListenUDP("udp", localaddr)
	if err != nil {
		return
	}
	defer func() {
		e := udpconn.Close()
		if err == nil {
			err = e
		}
	}()
	boundaddr := udpconn.LocalAddr().(*net.UDPAddr)
	packet := make([]byte, 0x30)
	t := time.Now()
	_, tz := t.Zone()
	tz /= 3600  
	binary.LittleEndian.PutUint32(packet[0x08:], uint32(tz))
	binary.LittleEndian.PutUint16(packet[0x0c:], uint16(t.Year()))
	packet[0x0e] = byte(t.Second())
	packet[0x0f] = byte(t.Minute())
	packet[0x10] = byte(t.Hour())
	packet[0x11] = byte(t.Weekday())
	packet[0x12] = byte(t.Day())
	packet[0x13] = byte(t.Month())
	ip := boundaddr.IP.To4()
	packet[0x18], packet[0x19], packet[0x1a], packet[0x1b] = ip[3], ip[2], ip[1], ip[0]  
	binary.LittleEndian.PutUint16(packet[0x1c:], uint16(boundaddr.Port))
	packet[0x26] = 0x06  
	sum := checksum(packet)
	binary.LittleEndian.PutUint16(packet[0x20:], sum)
	err = udpconn.SetDeadline(deadline)
	if err != nil {
		return
	}
	broadcastAddr := &net.UDPAddr{IP: net.IPv4bcast, Port: BroadLinkDevicePort}
	_, err = udpconn.WriteTo(packet, broadcastAddr)
	if err != nil {
		return
	}
	devlist = make([]Device, 0)
	resp := make([]byte, 2048)
	for {
		sz, raddr, e := udpconn.ReadFromUDP(resp)
		if ope, ok := e.(*net.OpError); ok {
			if ope.Timeout() {
				return
			}
		}
		if e != nil {
			err = e
			return
		}
		if sz == 0 {
			continue
		}
		r := resp[:sz]
		if !packetChecksumOK(r) {
			continue
		}
		if r[0x26] != 0x07 {  
			continue
		}
		var newdev Device
		newdev.Type = uint16(r[0x35])<<8 | uint16(r[0x34])
		newdev.UDPAddr = *raddr
		ip := net.IPv4(r[0x39], r[0x38], r[0x37], r[0x36])  
		if bytes.Compare(newdev.UDPAddr.IP.To4(), ip.To4()) != 0 {
			continue
		}
		newdev.MACAddr = make([]byte, 6)
		for i := 0; i < 6; i++ {
			newdev.MACAddr[5-i] = r[0x3a+i]
		}
		newdev.LocalAddr = *localaddr
		devlist = append(devlist, newdev)
	}
	return
}