301 lines
7.5 KiB
Go
301 lines
7.5 KiB
Go
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/ultrabeam"
|
|
"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
|
|
ultrabeam *ultrabeam.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"`
|
|
Ultrabeam *ultrabeam.Status `json:"ultrabeam"`
|
|
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
|
|
log.Printf("Initializing RotatorGenius: host=%s port=%d", dm.config.Devices.RotatorGenius.Host, dm.config.Devices.RotatorGenius.Port)
|
|
dm.rotatorGenius = rotatorgenius.New(
|
|
dm.config.Devices.RotatorGenius.Host,
|
|
dm.config.Devices.RotatorGenius.Port,
|
|
)
|
|
|
|
// Initialize Ultrabeam
|
|
log.Printf("Initializing Ultrabeam: host=%s port=%d", dm.config.Devices.Ultrabeam.Host, dm.config.Devices.Ultrabeam.Port)
|
|
dm.ultrabeam = ultrabeam.New(
|
|
dm.config.Devices.Ultrabeam.Host,
|
|
dm.config.Devices.Ultrabeam.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 device polling in background (non-blocking)
|
|
go func() {
|
|
if err := dm.powerGenius.Start(); err != nil {
|
|
log.Printf("Warning: Failed to start PowerGenius polling: %v", err)
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
if err := dm.tunerGenius.Start(); err != nil {
|
|
log.Printf("Warning: Failed to start TunerGenius polling: %v", err)
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
if err := dm.antennaGenius.Start(); err != nil {
|
|
log.Printf("Warning: Failed to start AntennaGenius polling: %v", err)
|
|
}
|
|
}()
|
|
|
|
log.Println("About to launch RotatorGenius goroutine...")
|
|
go func() {
|
|
log.Println("Starting RotatorGenius polling goroutine...")
|
|
if err := dm.rotatorGenius.Start(); err != nil {
|
|
log.Printf("Warning: Failed to start RotatorGenius polling: %v", err)
|
|
}
|
|
}()
|
|
log.Println("RotatorGenius goroutine launched")
|
|
|
|
log.Println("About to launch Ultrabeam goroutine...")
|
|
go func() {
|
|
log.Println("Starting Ultrabeam polling goroutine...")
|
|
if err := dm.ultrabeam.Start(); err != nil {
|
|
log.Printf("Warning: Failed to start Ultrabeam polling: %v", err)
|
|
}
|
|
}()
|
|
log.Println("Ultrabeam goroutine launched")
|
|
|
|
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()
|
|
}
|
|
if dm.ultrabeam != nil {
|
|
dm.ultrabeam.Stop()
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
// Ultrabeam
|
|
if ubStatus, err := dm.ultrabeam.GetStatus(); err == nil {
|
|
status.Ultrabeam = ubStatus
|
|
} else {
|
|
log.Printf("Ultrabeam 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
|
|
}
|
|
|
|
func (dm *DeviceManager) Ultrabeam() *ultrabeam.Client {
|
|
return dm.ultrabeam
|
|
}
|