package api import ( "log" "sync" "time" "git.rouggy.com/rouggy/ShackMaster/internal/config" "git.rouggy.com/rouggy/ShackMaster/internal/devices/antennagenius" "git.rouggy.com/rouggy/ShackMaster/internal/devices/powergenius" "git.rouggy.com/rouggy/ShackMaster/internal/devices/rotatorgenius" "git.rouggy.com/rouggy/ShackMaster/internal/devices/tunergenius" "git.rouggy.com/rouggy/ShackMaster/internal/devices/webswitch" "git.rouggy.com/rouggy/ShackMaster/internal/services/solar" "git.rouggy.com/rouggy/ShackMaster/internal/services/weather" ) type DeviceManager struct { config *config.Config webSwitch *webswitch.Client powerGenius *powergenius.Client tunerGenius *tunergenius.Client antennaGenius *antennagenius.Client rotatorGenius *rotatorgenius.Client solarClient *solar.Client weatherClient *weather.Client hub *Hub statusMu sync.RWMutex lastStatus *SystemStatus updateInterval time.Duration stopChan chan struct{} } type SystemStatus struct { WebSwitch *webswitch.Status `json:"webswitch"` PowerGenius *powergenius.Status `json:"power_genius"` TunerGenius *tunergenius.Status `json:"tuner_genius"` AntennaGenius *antennagenius.Status `json:"antenna_genius"` RotatorGenius *rotatorgenius.Status `json:"rotator_genius"` Solar *solar.SolarData `json:"solar"` Weather *weather.WeatherData `json:"weather"` Timestamp time.Time `json:"timestamp"` } func NewDeviceManager(cfg *config.Config, hub *Hub) *DeviceManager { return &DeviceManager{ config: cfg, hub: hub, updateInterval: 1 * time.Second, // Update status every second stopChan: make(chan struct{}), } } func (dm *DeviceManager) Initialize() error { log.Println("Initializing device manager...") // Initialize WebSwitch dm.webSwitch = webswitch.New(dm.config.Devices.WebSwitch.Host) // Initialize Power Genius dm.powerGenius = powergenius.New( dm.config.Devices.PowerGenius.Host, dm.config.Devices.PowerGenius.Port, ) // Initialize Tuner Genius dm.tunerGenius = tunergenius.New( dm.config.Devices.TunerGenius.Host, dm.config.Devices.TunerGenius.Port, ) // Initialize Antenna Genius dm.antennaGenius = antennagenius.New( dm.config.Devices.AntennaGenius.Host, dm.config.Devices.AntennaGenius.Port, ) // Initialize Rotator Genius dm.rotatorGenius = rotatorgenius.New( dm.config.Devices.RotatorGenius.Host, dm.config.Devices.RotatorGenius.Port, ) // Initialize Solar data client dm.solarClient = solar.New() // Initialize Weather client dm.weatherClient = weather.New( dm.config.Weather.OpenWeatherMapAPIKey, dm.config.Location.Latitude, dm.config.Location.Longitude, ) // Start PowerGenius continuous polling if err := dm.powerGenius.Start(); err != nil { log.Printf("Warning: Failed to start PowerGenius polling: %v", err) } log.Println("Device manager initialized") return nil } func (dm *DeviceManager) Start() error { log.Println("Starting device monitoring...") go dm.monitorDevices() return nil } func (dm *DeviceManager) Stop() { log.Println("Stopping device manager...") close(dm.stopChan) // Close all connections if dm.powerGenius != nil { dm.powerGenius.Close() } if dm.tunerGenius != nil { dm.tunerGenius.Close() } if dm.antennaGenius != nil { dm.antennaGenius.Close() } if dm.rotatorGenius != nil { dm.rotatorGenius.Close() } } func (dm *DeviceManager) monitorDevices() { ticker := time.NewTicker(dm.updateInterval) defer ticker.Stop() for { select { case <-ticker.C: dm.updateStatus() case <-dm.stopChan: return } } } func (dm *DeviceManager) updateStatus() { status := &SystemStatus{ Timestamp: time.Now(), } // Query all devices // WebSwitch - get actual relay states if wsStatus, err := dm.webSwitch.GetStatus(); err == nil { status.WebSwitch = wsStatus } else { log.Printf("WebSwitch error: %v", err) } // Power Genius if pgStatus, err := dm.powerGenius.GetStatus(); err == nil { status.PowerGenius = pgStatus } else { log.Printf("Power Genius error: %v", err) } // // Tuner Genius // if tgStatus, err := dm.tunerGenius.GetStatus(); err == nil { // status.TunerGenius = tgStatus // } else { // log.Printf("Tuner Genius error: %v", err) // } // // Antenna Genius // if agStatus, err := dm.antennaGenius.GetStatus(); err == nil { // status.AntennaGenius = agStatus // } else { // log.Printf("Antenna Genius error: %v", err) // } // // Rotator Genius // if rgStatus, err := dm.rotatorGenius.GetStatus(); err == nil { // status.RotatorGenius = rgStatus // } else { // log.Printf("Rotator Genius error: %v", err) // } // Solar Data (fetched every 15 minutes, cached) if solarData, err := dm.solarClient.GetSolarData(); err == nil { status.Solar = solarData } else { log.Printf("Solar data error: %v", err) } // Weather Data (fetched every 10 minutes, cached) if weatherData, err := dm.weatherClient.GetWeatherData(); err == nil { status.Weather = weatherData } else { log.Printf("Weather data error: %v", err) } // Update cached status dm.statusMu.Lock() dm.lastStatus = status dm.statusMu.Unlock() // Broadcast to all connected clients if dm.hub != nil { dm.hub.BroadcastStatusUpdate(status) } } func (dm *DeviceManager) GetStatus() *SystemStatus { dm.statusMu.RLock() defer dm.statusMu.RUnlock() if dm.lastStatus == nil { return &SystemStatus{ Timestamp: time.Now(), } } return dm.lastStatus } // Device control methods func (dm *DeviceManager) WebSwitch() *webswitch.Client { return dm.webSwitch } func (dm *DeviceManager) PowerGenius() *powergenius.Client { return dm.powerGenius } func (dm *DeviceManager) TunerGenius() *tunergenius.Client { return dm.tunerGenius } func (dm *DeviceManager) AntennaGenius() *antennagenius.Client { return dm.antennaGenius } func (dm *DeviceManager) RotatorGenius() *rotatorgenius.Client { return dm.rotatorGenius }