147 lines
2.8 KiB
Go
147 lines
2.8 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"`
|
|
}
|
|
|
|
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 {
|
|
for i := 1; i <= 5; i++ {
|
|
if err := c.TurnOn(i); err != nil {
|
|
return fmt.Errorf("failed to turn on relay %d: %w", i, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) AllOff() error {
|
|
for i := 1; i <= 5; i++ {
|
|
if err := c.TurnOff(i); err != nil {
|
|
return fmt.Errorf("failed to turn off relay %d: %w", i, 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),
|
|
}
|
|
|
|
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
|
|
}
|