mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Major improvements to device discovery system: 🔧 **SSDP Discovery Fixed**: - Fixed networking issue where SSDP used connected UDP socket instead of UDP listener - SSDP now properly receives unicast responses from multicast requests - UPnP discovery now works reliably and finds all MediaRenderer devices ✨ **Enhanced DiscoveredDevice Model**: - Added consistent URL fields (APIBaseURL, InfoURL) for all discovery methods - Added protocol-specific fields (UPnPLocation, UPnPUSN, MDNSHostname, etc.) - Added DiscoveryMethod tracking to show how devices were found - Added device merging support for same device found via multiple protocols 🚀 **Unified Discovery Improvements**: - Fixed device merging logic to properly combine protocol-specific data - Discovery methods now correctly show combinations like 'Configuration+SSDP/UPnP+mDNS/Bonjour' - Removed duplicate configuration device loading in individual services - All three discovery methods (SSDP, mDNS, Configuration) work together seamlessly 🛠 **Updated Tools & Examples**: - Updated soundtouch-cli to display new consistent field structure - Enhanced all example programs with better device information display - Added new unified discovery example demonstrating all three methods - Fixed context timeout issues in example programs 📋 **Comprehensive Testing**: - All tests updated and passing - Real-world validation with actual Bose SoundTouch devices - Confirmed discovery methods properly merge device data Every discovered device now has consistent http://host:port/info URLs regardless of discovery method, while preserving valuable protocol-specific metadata.
128 lines
3.7 KiB
Go
128 lines
3.7 KiB
Go
// Package main provides an example of discovering SoundTouch devices using UPnP.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/config"
|
|
"github.com/gesellix/bose-soundtouch/pkg/discovery"
|
|
)
|
|
|
|
func main() {
|
|
verbose := flag.Bool("verbose", false, "Enable verbose logging")
|
|
timeout := flag.Duration("timeout", 5*time.Second, "Discovery timeout")
|
|
|
|
flag.Parse()
|
|
|
|
// Configure logging
|
|
if *verbose {
|
|
log.SetOutput(os.Stdout)
|
|
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
|
|
} else {
|
|
log.SetOutput(os.Stderr)
|
|
}
|
|
|
|
fmt.Println("SoundTouch UPnP/SSDP Discovery Example")
|
|
fmt.Println("=====================================")
|
|
|
|
fmt.Printf("Timeout: %v, Verbose: %v\n", *timeout, *verbose)
|
|
fmt.Println()
|
|
|
|
// Create context with timeout (add buffer time)
|
|
ctx, cancel := context.WithTimeout(context.Background(), *timeout+2*time.Second)
|
|
defer cancel()
|
|
|
|
fmt.Println("Searching for SoundTouch devices via UPnP/SSDP...")
|
|
fmt.Println("This will send M-SEARCH requests to multicast address 239.255.255.250:1900")
|
|
|
|
if *verbose {
|
|
fmt.Println("Verbose logging enabled - watch for technical details...")
|
|
}
|
|
|
|
fmt.Println()
|
|
|
|
start := time.Now()
|
|
|
|
// Create a config that disables configured devices to test only UPnP
|
|
cfg := &config.Config{
|
|
DiscoveryTimeout: *timeout,
|
|
UPnPEnabled: true,
|
|
MDNSEnabled: false,
|
|
PreferredDevices: []config.DeviceConfig{}, // Empty to test only UPnP
|
|
CacheEnabled: false,
|
|
}
|
|
|
|
// Use the configured discovery service to isolate UPnP
|
|
configuredService := discovery.NewServiceWithConfig(cfg)
|
|
devices, err := configuredService.DiscoverDevices(ctx)
|
|
duration := time.Since(start)
|
|
|
|
fmt.Printf("Discovery completed in %v\n", duration)
|
|
fmt.Println()
|
|
|
|
if err != nil {
|
|
fmt.Printf("UPnP discovery completed with error: %v\n", err)
|
|
fmt.Println("Note: This might indicate network issues or no UPnP devices")
|
|
}
|
|
|
|
// Display results
|
|
if len(devices) == 0 {
|
|
fmt.Println("No SoundTouch devices found via UPnP/SSDP")
|
|
fmt.Println()
|
|
fmt.Println("Technical Status:")
|
|
|
|
if *verbose {
|
|
fmt.Println("✓ SSDP M-SEARCH request was sent (check logs above for details)")
|
|
fmt.Println("✓ UDP multicast connection established")
|
|
fmt.Println("✗ No devices responded with MediaRenderer service type")
|
|
} else {
|
|
fmt.Println("Run with --verbose flag for detailed technical information")
|
|
}
|
|
|
|
fmt.Println()
|
|
fmt.Println("This could mean:")
|
|
fmt.Println("- No SoundTouch devices on network")
|
|
fmt.Println("- Devices don't support UPnP/SSDP")
|
|
fmt.Println("- Network blocks multicast traffic (common in corporate networks)")
|
|
fmt.Println("- Firewall blocks UDP port 1900")
|
|
fmt.Println("- Devices are not advertising MediaRenderer service")
|
|
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Found %d SoundTouch device(s):\n", len(devices))
|
|
fmt.Println()
|
|
|
|
for i, device := range devices {
|
|
fmt.Printf("%d. %s\n", i+1, device.Name)
|
|
fmt.Printf(" Host: %s\n", device.Host)
|
|
fmt.Printf(" Port: %d\n", device.Port)
|
|
fmt.Printf(" API URL: http://%s:%d/\n", device.Host, device.Port)
|
|
fmt.Printf(" Info URL: %s\n", device.InfoURL)
|
|
|
|
if device.UPnPLocation != "" {
|
|
fmt.Printf(" UPnP Location: %s\n", device.UPnPLocation)
|
|
}
|
|
|
|
fmt.Printf(" Last seen: %s\n", device.LastSeen.Format("2006-01-02 15:04:05"))
|
|
fmt.Println()
|
|
}
|
|
|
|
fmt.Println("✓ UPnP/SSDP discovery completed successfully!")
|
|
fmt.Printf("✓ Found %d device(s) in %v\n", len(devices), duration)
|
|
|
|
if *verbose {
|
|
fmt.Println()
|
|
fmt.Println("Technical Details:")
|
|
fmt.Printf("- Multicast address used: 239.255.255.250:1900\n")
|
|
fmt.Printf("- Service type searched: urn:schemas-upnp-org:device:MediaRenderer:1\n")
|
|
fmt.Printf("- Discovery timeout: %v\n", *timeout)
|
|
fmt.Printf("- Protocol: UDP SSDP (Simple Service Discovery Protocol)\n")
|
|
}
|
|
}
|