correct bugs AG
This commit is contained in:
@@ -249,7 +249,6 @@ func (dm *DeviceManager) updateStatus() {
|
||||
// This prevents auto-track from using wrong direction before user changes it
|
||||
if !dm.ultrabeamDirectionSet {
|
||||
dm.ultrabeamDirection = ubStatus.Direction
|
||||
log.Printf("Auto-track: Initialized direction from Ultrabeam: %d", dm.ultrabeamDirection)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Ultrabeam error: %v", err)
|
||||
@@ -260,50 +259,45 @@ func (dm *DeviceManager) updateStatus() {
|
||||
tunerFreqKhz := int(status.TunerGenius.FreqA) // TunerGenius frequency is already in kHz
|
||||
ultrabeamFreqKhz := status.Ultrabeam.Frequency // Ultrabeam frequency in kHz
|
||||
|
||||
// Ignore invalid frequencies or out of Ultrabeam range (40M-6M)
|
||||
// This prevents retraction when slice is closed (FreqA becomes 0)
|
||||
// Ultrabeam VL2.3 only covers 7000-54000 kHz (40M to 6M)
|
||||
if tunerFreqKhz < 7000 || tunerFreqKhz > 54000 {
|
||||
return // Out of range, skip auto-track
|
||||
}
|
||||
|
||||
freqDiff := tunerFreqKhz - ultrabeamFreqKhz
|
||||
if freqDiff < 0 {
|
||||
freqDiff = -freqDiff
|
||||
}
|
||||
|
||||
// Convert diff to Hz for comparison with threshold (which is in Hz)
|
||||
freqDiffHz := freqDiff * 1000
|
||||
|
||||
// Don't send command if motors are already moving
|
||||
if status.Ultrabeam.MotorsMoving != 0 {
|
||||
// Motors moving - wait for them to finish
|
||||
return
|
||||
}
|
||||
|
||||
if freqDiffHz >= dm.freqThreshold {
|
||||
// Use user's explicitly set direction, or fallback to current Ultrabeam direction
|
||||
directionToUse := dm.ultrabeamDirection
|
||||
if !dm.ultrabeamDirectionSet && status.Ultrabeam.Direction != 0 {
|
||||
directionToUse = status.Ultrabeam.Direction
|
||||
// Only do auto-track if frequency is in Ultrabeam range (40M-6M: 7000-54000 kHz)
|
||||
// This prevents retraction when slice is closed (FreqA becomes 0) or on out-of-range bands
|
||||
if tunerFreqKhz >= 7000 && tunerFreqKhz <= 54000 {
|
||||
freqDiff := tunerFreqKhz - ultrabeamFreqKhz
|
||||
if freqDiff < 0 {
|
||||
freqDiff = -freqDiff
|
||||
}
|
||||
|
||||
// Check cooldown to prevent rapid fire commands
|
||||
timeSinceLastUpdate := time.Since(dm.lastFreqUpdateTime)
|
||||
if timeSinceLastUpdate < dm.freqUpdateCooldown {
|
||||
log.Printf("Auto-track: Cooldown active (%v remaining), skipping update", dm.freqUpdateCooldown-timeSinceLastUpdate)
|
||||
} else {
|
||||
log.Printf("Auto-track: Frequency differs by %d kHz, updating Ultrabeam to %d kHz (direction=%d)", freqDiff, tunerFreqKhz, directionToUse)
|
||||
// Convert diff to Hz for comparison with threshold (which is in Hz)
|
||||
freqDiffHz := freqDiff * 1000
|
||||
|
||||
// Send to Ultrabeam with saved or current direction
|
||||
if err := dm.ultrabeam.SetFrequency(tunerFreqKhz, directionToUse); err != nil {
|
||||
log.Printf("Auto-track: Failed to update Ultrabeam: %v (will retry)", err)
|
||||
} else {
|
||||
log.Printf("Auto-track: Successfully sent frequency to Ultrabeam")
|
||||
dm.lastFreqUpdateTime = time.Now() // Update cooldown timer
|
||||
// Don't send command if motors are already moving
|
||||
if status.Ultrabeam.MotorsMoving == 0 {
|
||||
if freqDiffHz >= dm.freqThreshold {
|
||||
// Use user's explicitly set direction, or fallback to current Ultrabeam direction
|
||||
directionToUse := dm.ultrabeamDirection
|
||||
if !dm.ultrabeamDirectionSet && status.Ultrabeam.Direction != 0 {
|
||||
directionToUse = status.Ultrabeam.Direction
|
||||
}
|
||||
|
||||
// Check cooldown to prevent rapid fire commands
|
||||
timeSinceLastUpdate := time.Since(dm.lastFreqUpdateTime)
|
||||
if timeSinceLastUpdate < dm.freqUpdateCooldown {
|
||||
log.Printf("Auto-track: Cooldown active (%v remaining), skipping update", dm.freqUpdateCooldown-timeSinceLastUpdate)
|
||||
} else {
|
||||
log.Printf("Auto-track: Frequency differs by %d kHz, updating Ultrabeam to %d kHz (direction=%d)", freqDiff, tunerFreqKhz, directionToUse)
|
||||
|
||||
// Send to Ultrabeam with saved or current direction
|
||||
if err := dm.ultrabeam.SetFrequency(tunerFreqKhz, directionToUse); err != nil {
|
||||
log.Printf("Auto-track: Failed to update Ultrabeam: %v (will retry)", err)
|
||||
} else {
|
||||
log.Printf("Auto-track: Successfully sent frequency to Ultrabeam")
|
||||
dm.lastFreqUpdateTime = time.Now() // Update cooldown timer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If out of range, simply skip auto-track but continue with status broadcast
|
||||
}
|
||||
|
||||
// Solar Data (fetched every 15 minutes, cached)
|
||||
|
||||
@@ -58,6 +58,7 @@ func (s *Server) SetupRoutes() *http.ServeMux {
|
||||
mux.HandleFunc("/api/ultrabeam/frequency", s.handleUltrabeamFrequency)
|
||||
mux.HandleFunc("/api/ultrabeam/retract", s.handleUltrabeamRetract)
|
||||
mux.HandleFunc("/api/ultrabeam/autotrack", s.handleUltrabeamAutoTrack)
|
||||
mux.HandleFunc("/api/ultrabeam/direction", s.handleUltrabeamDirection)
|
||||
|
||||
// Tuner endpoints
|
||||
mux.HandleFunc("/api/tuner/operate", s.handleTunerOperate)
|
||||
@@ -66,6 +67,7 @@ func (s *Server) SetupRoutes() *http.ServeMux {
|
||||
|
||||
// Antenna Genius endpoints
|
||||
mux.HandleFunc("/api/antenna/select", s.handleAntennaSelect)
|
||||
mux.HandleFunc("/api/antenna/deselect", s.handleAntennaDeselect)
|
||||
mux.HandleFunc("/api/antenna/reboot", s.handleAntennaReboot)
|
||||
|
||||
// Power Genius endpoints
|
||||
@@ -336,6 +338,33 @@ func (s *Server) handleAntennaSelect(w http.ResponseWriter, r *http.Request) {
|
||||
s.sendJSON(w, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
func (s *Server) handleAntennaDeselect(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Port int `json:"port"`
|
||||
Antenna int `json:"antenna"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Deselecting antenna %d from port %d", req.Antenna, req.Port)
|
||||
if err := s.deviceManager.AntennaGenius().DeselectAntenna(req.Port, req.Antenna); err != nil {
|
||||
log.Printf("Failed to deselect antenna: %v", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Successfully deselected antenna %d from port %d", req.Antenna, req.Port)
|
||||
|
||||
s.sendJSON(w, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
func (s *Server) handleAntennaReboot(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
@@ -414,6 +443,9 @@ func (s *Server) handleUltrabeamFrequency(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
// Save direction for auto-track to use
|
||||
s.deviceManager.SetUltrabeamDirection(req.Direction)
|
||||
|
||||
if err := s.deviceManager.Ultrabeam().SetFrequency(req.Frequency, req.Direction); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@@ -457,6 +489,27 @@ func (s *Server) handleUltrabeamAutoTrack(w http.ResponseWriter, r *http.Request
|
||||
s.sendJSON(w, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
func (s *Server) handleUltrabeamDirection(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Direction int `json:"direction"` // 0=normal, 1=180°, 2=bi-dir
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Just save the direction preference for auto-track to use
|
||||
s.deviceManager.SetUltrabeamDirection(req.Direction)
|
||||
|
||||
s.sendJSON(w, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
func (s *Server) sendJSON(w http.ResponseWriter, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(data)
|
||||
|
||||
@@ -178,21 +178,22 @@ func (c *Client) pollLoop() {
|
||||
|
||||
func (c *Client) initialize() error {
|
||||
// Get antenna list
|
||||
log.Println("AntennaGenius: Getting antenna list...")
|
||||
antennas, err := c.getAntennaList()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get antenna list: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("AntennaGenius: Found %d antennas", len(antennas))
|
||||
for i, ant := range antennas {
|
||||
log.Printf("AntennaGenius: Antenna %d: number=%d, name=%s", i, ant.Number, ant.Name)
|
||||
}
|
||||
|
||||
c.antennasMu.Lock()
|
||||
c.antennas = antennas
|
||||
c.antennasMu.Unlock()
|
||||
|
||||
// Subscribe to port updates
|
||||
if err := c.subscribeToPortUpdates(); err != nil {
|
||||
return fmt.Errorf("failed to subscribe: %w", err)
|
||||
}
|
||||
|
||||
// Initialize status
|
||||
// Initialize status BEFORE subscribing so parsePortStatus can update it
|
||||
c.statusMu.Lock()
|
||||
c.lastStatus = &Status{
|
||||
PortA: &PortStatus{},
|
||||
@@ -202,6 +203,23 @@ func (c *Client) initialize() error {
|
||||
}
|
||||
c.statusMu.Unlock()
|
||||
|
||||
log.Println("AntennaGenius: Status initialized, now subscribing to port updates...")
|
||||
|
||||
// Subscribe to port updates (this will parse and update port status)
|
||||
if err := c.subscribeToPortUpdates(); err != nil {
|
||||
return fmt.Errorf("failed to subscribe: %w", err)
|
||||
}
|
||||
|
||||
// Request initial status for both ports
|
||||
log.Println("AntennaGenius: Requesting additional port status...")
|
||||
_, _ = c.sendCommand("port get 1") // Port A
|
||||
_, _ = c.sendCommand("port get 2") // Port B
|
||||
|
||||
c.statusMu.RLock()
|
||||
log.Printf("AntennaGenius: Initialization complete - PortA.RxAnt=%d, PortB.RxAnt=%d",
|
||||
c.lastStatus.PortA.RxAnt, c.lastStatus.PortB.RxAnt)
|
||||
c.statusMu.RUnlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -334,6 +352,7 @@ func (c *Client) parseAntennaLine(line string) Antenna {
|
||||
func (c *Client) subscribeToPortUpdates() error {
|
||||
resp, err := c.sendCommand("sub port all")
|
||||
if err != nil {
|
||||
log.Printf("AntennaGenius: Failed to subscribe: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -347,6 +366,7 @@ func (c *Client) subscribeToPortUpdates() error {
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("AntennaGenius: Subscription complete")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -437,6 +457,20 @@ func (c *Client) SetAntenna(port, antenna int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// DeselectAntenna deselects an antenna from a port (sets rxant=00)
|
||||
// Command format: "C1|port set <port> rxant=00"
|
||||
func (c *Client) DeselectAntenna(port, antenna int) error {
|
||||
cmd := fmt.Sprintf("port set %d rxant=00", port)
|
||||
log.Printf("AntennaGenius: Sending deselect command: %s", cmd)
|
||||
resp, err := c.sendCommand(cmd)
|
||||
if err != nil {
|
||||
log.Printf("AntennaGenius: Deselect failed: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Printf("AntennaGenius: Deselect response: %s", resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reboot reboots the device
|
||||
func (c *Client) Reboot() error {
|
||||
_, err := c.sendCommand("reboot")
|
||||
|
||||
Reference in New Issue
Block a user