Add gateway and daemon boilerplate
This commit is contained in:
parent
bcb15b75e8
commit
72b0a690a6
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
httpUserAgent = "solar-toolkit (git.netflux.io)"
|
||||||
|
httpTimeout = time.Second * 5
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
inverterAddr string
|
||||||
|
gatewayEndpoint string
|
||||||
|
gatewayUsername string
|
||||||
|
gatewayPassword string
|
||||||
|
pollInterval time.Duration
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(&inverterAddr, "inverter-addr", "", "IP+port of solar inverter")
|
||||||
|
flag.StringVar(&gatewayEndpoint, "endpoint", "", "URL to post metrics to")
|
||||||
|
flag.StringVar(&gatewayUsername, "username", "", "HTTP basic auth username")
|
||||||
|
flag.StringVar(&gatewayPassword, "password", "", "HTTP basic auth password")
|
||||||
|
flag.DurationVar(&pollInterval, "pollInterval", time.Minute, "Poll interval, example: 60s")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if gatewayEndpoint == "" {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.Dial("udp", inverterAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error dialing: %s", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var inv inverter.ET
|
||||||
|
|
||||||
|
ticker := time.NewTicker(pollInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
client := http.Client{Timeout: httpTimeout}
|
||||||
|
|
||||||
|
for ; true; <-ticker.C {
|
||||||
|
runtimeData, err := inv.RuntimeData(context.Background(), conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching runtime data: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reqBody, err := json.Marshal(runtimeData)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error encoding runtime data: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, gatewayEndpoint, bytes.NewReader(reqBody))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error building request: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("content-type", "application/json")
|
||||||
|
req.Header.Set("user-agent", httpUserAgent)
|
||||||
|
if gatewayUsername != "" && gatewayPassword != "" {
|
||||||
|
req.SetBasicAuth(gatewayUsername, gatewayPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error sending request: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.Printf("unexpected HTTP response code: %d", resp.StatusCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Sent: %+v", runtimeData)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.netflux.io/rob/solar-toolkit/gateway/handler"
|
||||||
|
"git.netflux.io/rob/solar-toolkit/gateway/store"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultBindAddr = ":8888"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
databaseURL := os.Getenv("DATABASE_URL")
|
||||||
|
if databaseURL == "" {
|
||||||
|
log.Fatal("missing configuration DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
bindAddr := os.Getenv("BIND_ADDR")
|
||||||
|
if bindAddr == "" {
|
||||||
|
bindAddr = defaultBindAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("postgres", databaseURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not connect to database: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
store := store.NewSQL(db)
|
||||||
|
handler := handler.NewHandler(store)
|
||||||
|
srv := http.Server{
|
||||||
|
ReadTimeout: time.Second * 3,
|
||||||
|
WriteTimeout: time.Second * 3,
|
||||||
|
Handler: handler,
|
||||||
|
Addr: bindAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Listening on %s...", bindAddr)
|
||||||
|
if err := srv.ListenAndServe(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Store interface {
|
||||||
|
InsertETRuntimeData(*inverter.ETRuntimeData) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
store Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(store Store) *Handler { return &Handler{store: store} }
|
||||||
|
|
||||||
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PostgresStore struct {
|
||||||
|
db *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSQL(db *sqlx.DB) *PostgresStore {
|
||||||
|
return &PostgresStore{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PostgresStore) InsertETRuntimeData(runtimeData *inverter.ETRuntimeData) error {
|
||||||
|
return nil
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -3,6 +3,8 @@ module git.netflux.io/rob/solar-toolkit
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/jmoiron/sqlx v1.3.5
|
||||||
|
github.com/lib/pq v1.10.6
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
golang.org/x/exp v0.0.0-20220706164943-b4a6d9510983
|
golang.org/x/exp v0.0.0-20220706164943-b4a6d9510983
|
||||||
)
|
)
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -1,6 +1,15 @@
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||||
|
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||||
|
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|
Loading…
Reference in New Issue