Files
2026-01-10 03:26:17 +01:00

185 lines
3.9 KiB
Go

package webswitch
import (
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
)
type Client struct {
host string
httpClient *http.Client
}
type Status struct {
Relays []RelayState `json:"relays"`
Connected bool `json:"connected"`
}
type RelayState struct {
Number int `json:"number"`
State bool `json:"state"`
}
func New(host string) *Client {
return &Client{
host: host,
httpClient: &http.Client{
Timeout: 5 * time.Second,
},
}
}
func (c *Client) SetRelay(relay int, state bool) error {
if relay < 1 || relay > 5 {
return fmt.Errorf("relay number must be between 1 and 5")
}
action := "off"
if state {
action = "on"
}
url := fmt.Sprintf("http://%s/relaycontrol/%s/%d", c.host, action, relay)
resp, err := c.httpClient.Get(url)
if err != nil {
return fmt.Errorf("failed to control relay: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
}
return nil
}
func (c *Client) TurnOn(relay int) error {
return c.SetRelay(relay, true)
}
func (c *Client) TurnOff(relay int) error {
return c.SetRelay(relay, false)
}
func (c *Client) AllOn() error {
// Sequence for ALL ON:
// 1. Turn on relays 1, 2, 3, 5 immediately
// 2. Wait 5 seconds
// 3. Turn on relay 4 (Flex Radio Start)
// Turn on relays 1, 2, 3, 5
for _, relay := range []int{1, 2, 3, 5} {
if err := c.TurnOn(relay); err != nil {
return fmt.Errorf("failed to turn on relay %d: %w", relay, err)
}
}
// Wait 5 seconds for power supply to stabilize
time.Sleep(5 * time.Second)
// Turn on relay 4 (Flex Radio)
if err := c.TurnOn(4); err != nil {
return fmt.Errorf("failed to turn on relay 4: %w", err)
}
return nil
}
func (c *Client) AllOff() error {
// Sequence for ALL OFF:
// 1. Turn off relay 4 (Flex Radio) immediately
// 2. Turn off relays 2, 3, 5 immediately
// 3. Wait 35 seconds for Flex Radio to shut down
// 4. Turn off relay 1 (Power Supply)
// Turn off relay 4 (Flex Radio)
if err := c.TurnOff(4); err != nil {
return fmt.Errorf("failed to turn off relay 4: %w", err)
}
// Turn off relays 2, 3, 5
for _, relay := range []int{2, 3, 5} {
if err := c.TurnOff(relay); err != nil {
return fmt.Errorf("failed to turn off relay %d: %w", relay, err)
}
}
// Wait 35 seconds for Flex Radio to shut down properly
time.Sleep(35 * time.Second)
// Turn off relay 1 (Power Supply)
if err := c.TurnOff(1); err != nil {
return fmt.Errorf("failed to turn off relay 1: %w", err)
}
return nil
}
// GetStatus queries the actual state of all relays
func (c *Client) GetStatus() (*Status, error) {
url := fmt.Sprintf("http://%s/relaystate/get2/1$2$3$4$5$", c.host)
resp, err := c.httpClient.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to get relay status: %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)
}
// Parse response format: "1,1\n2,1\n3,1\n4,1\n5,0\n"
status := &Status{
Relays: make([]RelayState, 0, 5),
Connected: true,
}
lines := strings.Split(strings.TrimSpace(string(body)), "\n")
for _, line := range lines {
parts := strings.Split(strings.TrimSpace(line), ",")
if len(parts) != 2 {
continue
}
relayNum, err := strconv.Atoi(parts[0])
if err != nil {
continue
}
relayState, err := strconv.Atoi(parts[1])
if err != nil {
continue
}
status.Relays = append(status.Relays, RelayState{
Number: relayNum,
State: relayState == 1,
})
}
return status, nil
}
// Ping checks if the device is reachable
func (c *Client) Ping() error {
url := fmt.Sprintf("http://%s/", c.host)
resp, err := c.httpClient.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}