Replace --broadcast flag with per-universe target config
- Remove --broadcast CLI flag - Add [[target]] config section for per-universe destination addresses - Each ArtNet output universe can have its own target IP (broadcast or unicast) - ArtPoll discovery broadcasts to all unique target addresses - Falls back to configured target when no nodes discovered for universe 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,25 +20,27 @@ type Node struct {
|
||||
|
||||
// Discovery handles ArtNet node discovery
|
||||
type Discovery struct {
|
||||
sender *Sender
|
||||
nodes map[string]*Node // keyed by IP string
|
||||
nodesMu sync.RWMutex
|
||||
localIP [4]byte
|
||||
shortName string
|
||||
longName string
|
||||
universes []Universe
|
||||
done chan struct{}
|
||||
sender *Sender
|
||||
nodes map[string]*Node // keyed by IP string
|
||||
nodesMu sync.RWMutex
|
||||
localIP [4]byte
|
||||
shortName string
|
||||
longName string
|
||||
universes []Universe
|
||||
pollTargets []*net.UDPAddr
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// NewDiscovery creates a new discovery handler
|
||||
func NewDiscovery(sender *Sender, shortName, longName string, universes []Universe) *Discovery {
|
||||
func NewDiscovery(sender *Sender, shortName, longName string, universes []Universe, pollTargets []*net.UDPAddr) *Discovery {
|
||||
return &Discovery{
|
||||
sender: sender,
|
||||
nodes: make(map[string]*Node),
|
||||
shortName: shortName,
|
||||
longName: longName,
|
||||
universes: universes,
|
||||
done: make(chan struct{}),
|
||||
sender: sender,
|
||||
nodes: make(map[string]*Node),
|
||||
shortName: shortName,
|
||||
longName: longName,
|
||||
universes: universes,
|
||||
pollTargets: pollTargets,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,10 +59,8 @@ func (d *Discovery) Stop() {
|
||||
}
|
||||
|
||||
func (d *Discovery) pollLoop() {
|
||||
// Send initial poll
|
||||
if err := d.sender.SendPoll(); err != nil {
|
||||
log.Printf("failed to send ArtPoll: %v", err)
|
||||
}
|
||||
// Send initial poll to all targets
|
||||
d.sendPolls()
|
||||
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
@@ -73,15 +73,21 @@ func (d *Discovery) pollLoop() {
|
||||
case <-d.done:
|
||||
return
|
||||
case <-ticker.C:
|
||||
if err := d.sender.SendPoll(); err != nil {
|
||||
log.Printf("failed to send ArtPoll: %v", err)
|
||||
}
|
||||
d.sendPolls()
|
||||
case <-cleanupTicker.C:
|
||||
d.cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Discovery) sendPolls() {
|
||||
for _, target := range d.pollTargets {
|
||||
if err := d.sender.SendPoll(target); err != nil {
|
||||
log.Printf("failed to send ArtPoll to %s: %v", target.IP, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Discovery) cleanup() {
|
||||
d.nodesMu.Lock()
|
||||
defer d.nodesMu.Unlock()
|
||||
|
||||
@@ -7,14 +7,13 @@ import (
|
||||
|
||||
// Sender sends ArtNet packets
|
||||
type Sender struct {
|
||||
conn *net.UDPConn
|
||||
broadcastAddr *net.UDPAddr
|
||||
sequences map[Universe]uint8
|
||||
seqMu sync.Mutex
|
||||
conn *net.UDPConn
|
||||
sequences map[Universe]uint8
|
||||
seqMu sync.Mutex
|
||||
}
|
||||
|
||||
// NewSender creates a new ArtNet sender
|
||||
func NewSender(broadcastAddr string) (*Sender, error) {
|
||||
func NewSender() (*Sender, error) {
|
||||
// Create a UDP socket for sending
|
||||
conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
@@ -27,22 +26,9 @@ func NewSender(broadcastAddr string) (*Sender, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
broadcast, err := net.ResolveUDPAddr("udp4", broadcastAddr+":"+string(rune(Port)))
|
||||
if err != nil {
|
||||
// Try parsing as IP:Port
|
||||
broadcast, err = net.ResolveUDPAddr("udp4", broadcastAddr)
|
||||
if err != nil {
|
||||
broadcast = &net.UDPAddr{
|
||||
IP: net.ParseIP(broadcastAddr),
|
||||
Port: Port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &Sender{
|
||||
conn: conn,
|
||||
broadcastAddr: broadcast,
|
||||
sequences: make(map[Universe]uint8),
|
||||
conn: conn,
|
||||
sequences: make(map[Universe]uint8),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -62,15 +48,10 @@ func (s *Sender) SendDMX(addr *net.UDPAddr, universe Universe, data []byte) erro
|
||||
return err
|
||||
}
|
||||
|
||||
// SendDMXBroadcast sends a DMX packet to the broadcast address
|
||||
func (s *Sender) SendDMXBroadcast(universe Universe, data []byte) error {
|
||||
return s.SendDMX(s.broadcastAddr, universe, data)
|
||||
}
|
||||
|
||||
// SendPoll sends an ArtPoll packet to the broadcast address
|
||||
func (s *Sender) SendPoll() error {
|
||||
// SendPoll sends an ArtPoll packet to the specified address
|
||||
func (s *Sender) SendPoll(addr *net.UDPAddr) error {
|
||||
pkt := BuildPollPacket()
|
||||
_, err := s.conn.WriteToUDP(pkt, s.broadcastAddr)
|
||||
_, err := s.conn.WriteToUDP(pkt, addr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -85,8 +66,3 @@ func (s *Sender) SendPollReply(addr *net.UDPAddr, localIP [4]byte, shortName, lo
|
||||
func (s *Sender) Close() error {
|
||||
return s.conn.Close()
|
||||
}
|
||||
|
||||
// BroadcastAddr returns the configured broadcast address
|
||||
func (s *Sender) BroadcastAddr() *net.UDPAddr {
|
||||
return s.broadcastAddr
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user