178 lines
5.0 KiB
Go
178 lines
5.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/gorilla/websocket"
|
|
"google.golang.org/protobuf/proto"
|
|
"odroid-tui/pb"
|
|
)
|
|
|
|
func scanWifi(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/wifi/scan", d.IP)
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
client := &http.Client{Timeout: 10 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
var list []WifiAP
|
|
if err := json.NewDecoder(resp.Body).Decode(&list); err != nil {
|
|
return err
|
|
}
|
|
return WifiScanListMsg(list)
|
|
}
|
|
}
|
|
|
|
func fetchSettings(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/setting", d.IP)
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
client := &http.Client{Timeout: 3 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
var cfg SettingsPayload
|
|
if err := json.NewDecoder(resp.Body).Decode(&cfg); err != nil {
|
|
return err
|
|
}
|
|
return SettingsFetchedMsg(cfg)
|
|
}
|
|
}
|
|
|
|
func saveSettingsMap(d ConnectionDetails, payload interface{}) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/setting", d.IP)
|
|
jsonBytes, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
client := &http.Client{Timeout: 5 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("Save Failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 200 {
|
|
return fmt.Errorf("Save Error: %d", resp.StatusCode)
|
|
}
|
|
return ActionDoneMsg{}
|
|
}
|
|
}
|
|
|
|
func rebootDevice(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/reboot", d.IP)
|
|
req, _ := http.NewRequest("POST", url, nil)
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
client := &http.Client{Timeout: 2 * time.Second}
|
|
client.Do(req)
|
|
return ActionDoneMsg{}
|
|
}
|
|
}
|
|
|
|
func performLogin(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/login", d.IP)
|
|
payload := map[string]string{"username": d.Username, "password": d.Password}
|
|
jsonBytes, _ := json.Marshal(payload)
|
|
client := &http.Client{Timeout: 5 * time.Second}
|
|
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonBytes))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 200 {
|
|
return fmt.Errorf("Login Error: %d", resp.StatusCode)
|
|
}
|
|
var res map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&res)
|
|
return LoginSuccessMsg(res["token"])
|
|
}
|
|
}
|
|
|
|
func fetchInitialState(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/control", d.IP)
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
client := &http.Client{Timeout: 3 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
defer resp.Body.Close()
|
|
var res InitApiResponse
|
|
json.NewDecoder(resp.Body).Decode(&res)
|
|
return InitStateMsg{MainOn: res.Load12vOn, UsbOn: res.Load5vOn}
|
|
}
|
|
}
|
|
|
|
func toggleLoad(d ConnectionDetails, key string, state bool) tea.Cmd {
|
|
return func() tea.Msg {
|
|
url := fmt.Sprintf("http://%s/api/control", d.IP)
|
|
payload := map[string]interface{}{key: state}
|
|
jsonBytes, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
|
|
req.Header.Set("Authorization", "Bearer "+d.Token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
client := &http.Client{Timeout: 1 * time.Second}
|
|
client.Do(req)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func connectWebSocket(d ConnectionDetails) tea.Cmd {
|
|
return func() tea.Msg {
|
|
u := fmt.Sprintf("ws://%s/ws?token=%s", d.IP, d.Token)
|
|
conn, _, err := websocket.DefaultDialer.Dial(u, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return waitForWebSocketMessage(conn)()
|
|
}
|
|
}
|
|
|
|
func waitForWebSocketMessage(conn *websocket.Conn) tea.Cmd {
|
|
return func() tea.Msg {
|
|
_, message, err := conn.ReadMessage()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var status pb.StatusMessage
|
|
if err := proto.Unmarshal(message, &status); err == nil {
|
|
conv := func(s *pb.SensorChannelData) *PowerMetrics {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
return &PowerMetrics{Voltage: float64(s.GetVoltage()), Current: float64(s.GetCurrent()), Power: float64(s.GetPower())}
|
|
}
|
|
msg := WsPartialMsg{Conn: conn}
|
|
if s := status.GetSensorData(); s != nil {
|
|
msg.Vin = conv(s.GetVin())
|
|
msg.Main = conv(s.GetMain())
|
|
msg.Usb = conv(s.GetUsb())
|
|
}
|
|
if w := status.GetWifiStatus(); w != nil {
|
|
msg.Wifi = &WifiInfo{SSID: w.GetSsid(), RSSI: int(w.GetRssi())}
|
|
}
|
|
if sw := status.GetSwStatus(); sw != nil {
|
|
msg.Sw = &SwitchInfo{MainOn: sw.GetMain(), UsbOn: sw.GetUsb()}
|
|
}
|
|
return msg
|
|
}
|
|
return waitForWebSocketMessage(conn)
|
|
}
|
|
}
|