correct bugs AG

This commit is contained in:
2026-01-10 23:33:47 +01:00
parent bcf58b208b
commit 46ee44c6c9
11 changed files with 197 additions and 246 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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")