97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package solar
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// SolarData contains current solar and geomagnetic conditions
|
|
type SolarData struct {
|
|
SolarFluxIndex int `json:"sfi"` // Solar Flux Index
|
|
Sunspots int `json:"sunspots"` // Number of sunspots
|
|
AIndex int `json:"a_index"` // A-index (geomagnetic activity)
|
|
KIndex int `json:"k_index"` // K-index (geomagnetic activity)
|
|
GeomagField string `json:"geomag"` // Geomagnetic field status
|
|
UpdatedAt string `json:"updated"` // Last update time
|
|
}
|
|
|
|
// HamQSLResponse matches the XML structure from hamqsl.com
|
|
type HamQSLResponse struct {
|
|
XMLName xml.Name `xml:"solar"`
|
|
SolarData SolarDataXML `xml:"solardata"`
|
|
}
|
|
|
|
type SolarDataXML struct {
|
|
Updated string `xml:"updated"`
|
|
SolarFlux string `xml:"solarflux"`
|
|
AIndex string `xml:"aindex"`
|
|
KIndex string `xml:"kindex"`
|
|
Sunspots string `xml:"sunspots"`
|
|
GeomagField string `xml:"geomagfield"`
|
|
}
|
|
|
|
type Client struct {
|
|
httpClient *http.Client
|
|
lastUpdate time.Time
|
|
cachedData *SolarData
|
|
}
|
|
|
|
func New() *Client {
|
|
return &Client{
|
|
httpClient: &http.Client{
|
|
Timeout: 10 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetSolarData fetches current solar data from HamQSL
|
|
// Data is cached for 15 minutes to avoid excessive requests
|
|
func (c *Client) GetSolarData() (*SolarData, error) {
|
|
// Return cached data if less than 15 minutes old
|
|
if c.cachedData != nil && time.Since(c.lastUpdate) < 15*time.Minute {
|
|
return c.cachedData, nil
|
|
}
|
|
|
|
resp, err := c.httpClient.Get("http://www.hamqsl.com/solarxml.php")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch solar data: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read response: %w", err)
|
|
}
|
|
|
|
var hamqslData HamQSLResponse
|
|
if err := xml.Unmarshal(body, &hamqslData); err != nil {
|
|
return nil, fmt.Errorf("failed to parse XML: %w", err)
|
|
}
|
|
|
|
// Parse the data
|
|
solarData := &SolarData{
|
|
GeomagField: hamqslData.SolarData.GeomagField,
|
|
UpdatedAt: hamqslData.SolarData.Updated,
|
|
}
|
|
|
|
// Parse numeric values (trim spaces)
|
|
fmt.Sscanf(strings.TrimSpace(hamqslData.SolarData.SolarFlux), "%d", &solarData.SolarFluxIndex)
|
|
fmt.Sscanf(strings.TrimSpace(hamqslData.SolarData.AIndex), "%d", &solarData.AIndex)
|
|
fmt.Sscanf(strings.TrimSpace(hamqslData.SolarData.KIndex), "%d", &solarData.KIndex)
|
|
fmt.Sscanf(strings.TrimSpace(hamqslData.SolarData.Sunspots), "%d", &solarData.Sunspots)
|
|
|
|
// Cache the data
|
|
c.cachedData = solarData
|
|
c.lastUpdate = time.Now()
|
|
|
|
return solarData, nil
|
|
}
|