parent
1e509e4f6e
commit
b816ae43c0
3 changed files with 27 additions and 90 deletions
|
|
@ -20,7 +20,7 @@ import (
|
|||
"github.com/evcc-io/evcc/charger/warp"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/icholy/digest"
|
||||
"github.com/jpfielding/go-http-digest/pkg/digest"
|
||||
)
|
||||
|
||||
type WarpWS struct {
|
||||
|
|
@ -117,10 +117,7 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
}
|
||||
wb.pmHelper = request.NewHelper(wb.log)
|
||||
if cc.EnergyManagerUser != "" {
|
||||
wb.pmHelper.Client.Transport = &digest.Transport{
|
||||
Username: cc.EnergyManagerUser,
|
||||
Password: cc.EnergyManagerPassword,
|
||||
}
|
||||
wb.pmHelper.Client.Transport = digest.NewTransport(cc.EnergyManagerUser, cc.EnergyManagerPassword, wb.pmHelper.Client.Transport)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,10 +156,7 @@ func NewWarpWS(ctx context.Context, uri, user, password string, meterIndex uint)
|
|||
|
||||
client := request.NewHelper(log)
|
||||
if user != "" {
|
||||
client.Client.Transport = &digest.Transport{
|
||||
Username: user,
|
||||
Password: password,
|
||||
}
|
||||
client.Client.Transport = digest.NewTransport(user, password, client.Client.Transport)
|
||||
}
|
||||
|
||||
w := &WarpWS{
|
||||
|
|
@ -174,87 +168,37 @@ func NewWarpWS(ctx context.Context, uri, user, password string, meterIndex uint)
|
|||
metersValuesTopic: fmt.Sprintf("meters/%d/values", meterIndex),
|
||||
}
|
||||
|
||||
uri, err := parseURI(w.uri, true)
|
||||
if err != nil {
|
||||
w.log.DEBUG.Println(err)
|
||||
if uri == "" {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
go w.run(ctx, uri, user, password)
|
||||
go w.run(ctx)
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *WarpWS) run(ctx context.Context, uri, user, pass string) {
|
||||
bo := backoff.NewExponentialBackOff(
|
||||
backoff.WithMaxInterval(30*time.Second),
|
||||
backoff.WithMaxElapsedTime(0))
|
||||
|
||||
for ctx.Err() == nil {
|
||||
w.log.DEBUG.Printf("ws connecting to %s", uri)
|
||||
|
||||
conn, resp, err := dialWebsocket(ctx, uri, user, pass)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if conn != nil {
|
||||
conn.Close(websocket.StatusInternalError, "dial failed")
|
||||
}
|
||||
w.log.ERROR.Printf("ws dial to %s failed: %v", uri, err)
|
||||
} else {
|
||||
w.log.DEBUG.Printf("ws connected to %s", uri)
|
||||
bo.Reset()
|
||||
|
||||
if err := w.handleConnection(ctx, conn); err != nil {
|
||||
w.log.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(bo.NextBackOff()):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dialWebsocket(ctx context.Context, wsURL, user, pass string) (*websocket.Conn, *http.Response, error) {
|
||||
conn, resp, err := websocket.Dial(ctx, wsURL, nil)
|
||||
if err == nil {
|
||||
return conn, resp, err
|
||||
}
|
||||
|
||||
// Extract challeng from response
|
||||
if resp == nil {
|
||||
return nil, nil, fmt.Errorf("no response on websocket dial")
|
||||
}
|
||||
www := resp.Header.Get("WWW-Authenticate")
|
||||
|
||||
chal, err := digest.ParseChallenge(www)
|
||||
func (w *WarpWS) run(ctx context.Context) {
|
||||
uri, err := parseURI(w.uri, true)
|
||||
if err != nil {
|
||||
return nil, resp, fmt.Errorf("digest parse error: %w", err)
|
||||
w.log.DEBUG.Println(err)
|
||||
if uri == "" {
|
||||
return
|
||||
}
|
||||
}
|
||||
w.log.TRACE.Printf("connecting to %s …", uri)
|
||||
|
||||
cred, _ := digest.Digest(chal, digest.Options{
|
||||
Username: user,
|
||||
Password: pass,
|
||||
Method: "GET",
|
||||
URI: wsURL,
|
||||
Count: 1,
|
||||
})
|
||||
resp.Body.Close()
|
||||
bo := backoff.NewExponentialBackOff(backoff.WithMaxElapsedTime(0))
|
||||
for ctx.Err() == nil {
|
||||
conn, _, err := websocket.Dial(ctx, uri, nil)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(bo.NextBackOff())
|
||||
continue
|
||||
}
|
||||
|
||||
// Dial with Digest Auth
|
||||
dialer := websocket.DialOptions{
|
||||
HTTPHeader: http.Header{
|
||||
"Authorization": []string{cred.String()},
|
||||
},
|
||||
bo.Reset()
|
||||
if err := w.handleConnection(ctx, conn); err != nil {
|
||||
w.log.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
return websocket.Dial(ctx, wsURL, &dialer)
|
||||
}
|
||||
|
||||
func parseURI(uri string, toWS bool) (string, error) {
|
||||
|
|
@ -294,9 +238,9 @@ func (w *WarpWS) handleConnection(ctx context.Context, conn *websocket.Conn) err
|
|||
return err
|
||||
}
|
||||
|
||||
w.log.TRACE.Printf("%s ws event %s: %s", w.uri, event.Topic, event.Payload)
|
||||
w.log.TRACE.Printf("ws event %s: %s", event.Topic, event.Payload)
|
||||
if err := w.handleEvent(event.Topic, event.Payload); err != nil {
|
||||
w.log.ERROR.Printf("bad payload from %s for topic %s: %v", w.uri, event.Topic, err)
|
||||
w.log.ERROR.Printf("bad payload for topic %s: %v", event.Topic, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -387,7 +331,6 @@ func (w *WarpWS) hasFeature(feature string) bool {
|
|||
|
||||
var f []string
|
||||
if err := w.GetJSON(uri, &f); err == nil {
|
||||
w.log.DEBUG.Printf("%s features response: %s", w.uri, f)
|
||||
w.mu.Lock()
|
||||
w.features = f
|
||||
w.mu.Unlock()
|
||||
|
|
@ -495,7 +438,6 @@ func (w *WarpWS) disablePhaseAutoSwitch() error {
|
|||
uri := fmt.Sprintf("%s/evse/phase_auto_switch", w.uri)
|
||||
req, _ := request.New(http.MethodPost, uri, request.MarshalJSON(map[string]bool{"enabled": false}), request.JSONEncoding)
|
||||
_, err := w.Do(req)
|
||||
w.log.DEBUG.Println("disable phase auto switch was successful")
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -55,7 +55,6 @@ require (
|
|||
github.com/hashicorp/go-version v1.8.0
|
||||
github.com/hasura/go-graphql-client v0.15.1
|
||||
github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83
|
||||
github.com/icholy/digest v1.1.0
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.14.0
|
||||
github.com/insomniacslk/tapo v1.0.2
|
||||
github.com/itchyny/gojq v0.12.18
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -399,8 +399,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
|
||||
github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
|
|
@ -1068,8 +1066,6 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue