97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
|
package api
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"log/slog"
|
||
|
|
||
|
"code.jhot.me/jhot/hats/internal/nats"
|
||
|
"code.jhot.me/jhot/hats/pkg/config"
|
||
|
"code.jhot.me/jhot/hats/pkg/homeassistant"
|
||
|
"github.com/go-chi/chi/middleware"
|
||
|
"github.com/go-chi/chi/v5"
|
||
|
"github.com/go-chi/render"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
cfg *config.HatsConfig
|
||
|
logger *slog.Logger
|
||
|
server http.Server
|
||
|
haClient *homeassistant.RestClient
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
HA_STATE_PREFIX = "homeassistant.states"
|
||
|
)
|
||
|
|
||
|
func Listen(parentLogger *slog.Logger) {
|
||
|
logger = parentLogger
|
||
|
cfg = config.FromEnvironment()
|
||
|
haClient = homeassistant.NewRestClient(cfg.HomeAssistantBaseUrl, cfg.HomeAssistantToken)
|
||
|
router := chi.NewRouter()
|
||
|
|
||
|
router.Use(middleware.RequestID)
|
||
|
router.Use(middleware.RealIP)
|
||
|
router.Use(middleware.Recoverer)
|
||
|
router.Use(middleware.Timeout(60 * time.Second))
|
||
|
|
||
|
router.Get(`/api/state/{entityId}`, func(w http.ResponseWriter, r *http.Request) {
|
||
|
logger.Debug(fmt.Sprintf("%s %s", r.Method, r.URL.Path), "method", r.Method, "path", r.URL.Path, "address", r.RemoteAddr)
|
||
|
entityId := chi.URLParam(r, "entityId")
|
||
|
|
||
|
kvVal, err := nats.GetKeyValue(fmt.Sprintf("%s.%s", HA_STATE_PREFIX, entityId))
|
||
|
if err == nil && len(kvVal) > 0 {
|
||
|
w.Write(kvVal)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
data, err := haClient.GetState(entityId)
|
||
|
if err != nil {
|
||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nats.SetKeyValueString(fmt.Sprintf("%s.%s", HA_STATE_PREFIX, entityId), data.State)
|
||
|
render.PlainText(w, r, data.State)
|
||
|
})
|
||
|
|
||
|
router.Post("/api/state/{entityId}/{service}", func(w http.ResponseWriter, r *http.Request) {
|
||
|
logger.Debug(fmt.Sprintf("%s %s", r.Method, r.URL.Path), "method", r.Method, "path", r.URL.Path, "address", r.RemoteAddr)
|
||
|
entityId := chi.URLParam(r, "entityId")
|
||
|
service := chi.URLParam(r, "service")
|
||
|
|
||
|
var extras map[string]string
|
||
|
err := render.DecodeJSON(r.Body, &extras)
|
||
|
var haErr error
|
||
|
if err == nil && len(extras) > 0 {
|
||
|
haErr = haClient.CallService(entityId, service, extras)
|
||
|
} else {
|
||
|
haErr = haClient.CallService(entityId, service)
|
||
|
}
|
||
|
|
||
|
if haErr != nil {
|
||
|
logger.Error("Error setting state", "error", haErr)
|
||
|
http.Error(w, fmt.Sprintf("error proxying request: %s", haErr.Error()), http.StatusInternalServerError)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
render.Status(r, http.StatusOK)
|
||
|
render.PlainText(w, r, "OK")
|
||
|
})
|
||
|
|
||
|
server = http.Server{
|
||
|
Addr: ":8888",
|
||
|
Handler: router,
|
||
|
}
|
||
|
|
||
|
go server.ListenAndServe()
|
||
|
}
|
||
|
|
||
|
func Close() {
|
||
|
if server.Addr != "" {
|
||
|
server.Close()
|
||
|
}
|
||
|
}
|