Simplify powerwall login
This commit is contained in:
parent
15a0648cb0
commit
84eecff4a1
2 changed files with 50 additions and 48 deletions
31
meter/powerwall/powerwall.go
Normal file
31
meter/powerwall/powerwall.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package powerwall
|
||||
|
||||
// credits to https://github.com/vloschiavo/powerwall2
|
||||
|
||||
// URIs
|
||||
const (
|
||||
MeterURI = "/api/meters/aggregates"
|
||||
BatteryURI = "/api/system_status/soe"
|
||||
LoginURI = "/api/login/Basic"
|
||||
)
|
||||
|
||||
// MeterResponse is the /api/system_status/aggregates response
|
||||
type MeterResponse map[string]struct {
|
||||
LastCommunicationTime string `json:"last_communication_time"`
|
||||
InstantPower float64 `json:"instant_power"`
|
||||
InstantReactivePower float64 `json:"instant_reactive_power"`
|
||||
InstantApparentPower float64 `json:"instant_apparent_power"`
|
||||
Frequency float64 `json:"frequency"`
|
||||
EnergyExported float64 `json:"energy_exported"`
|
||||
EnergyImported float64 `json:"energy_imported"`
|
||||
InstantAverageVoltage float64 `json:"instant_average_voltage"`
|
||||
InstantTotalCurrent float64 `json:"instant_total_current"`
|
||||
IACurrent float64 `json:"i_a_current"`
|
||||
IBCurrent float64 `json:"i_b_current"`
|
||||
ICCurrent float64 `json:"i_c_current"`
|
||||
}
|
||||
|
||||
// BatteryResponse is the /api/system_status/soe response
|
||||
type BatteryResponse struct {
|
||||
Percentage float64 `json:"percentage"`
|
||||
}
|
||||
|
|
@ -1,46 +1,21 @@
|
|||
package meter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/meter/powerwall"
|
||||
"github.com/andig/evcc/util"
|
||||
"github.com/andig/evcc/util/request"
|
||||
)
|
||||
|
||||
// credits to https://github.com/vloschiavo/powerwall2
|
||||
|
||||
const (
|
||||
teslaMeterURI = "/api/meters/aggregates"
|
||||
teslaBatteryURI = "/api/system_status/soe"
|
||||
teslaLoginURI = "/api/login/Basic"
|
||||
)
|
||||
|
||||
type teslaMeterResponse map[string]struct {
|
||||
LastCommunicationTime string `json:"last_communication_time"`
|
||||
InstantPower float64 `json:"instant_power"`
|
||||
InstantReactivePower float64 `json:"instant_reactive_power"`
|
||||
InstantApparentPower float64 `json:"instant_apparent_power"`
|
||||
Frequency float64 `json:"frequency"`
|
||||
EnergyExported float64 `json:"energy_exported"`
|
||||
EnergyImported float64 `json:"energy_imported"`
|
||||
InstantAverageVoltage float64 `json:"instant_average_voltage"`
|
||||
InstantTotalCurrent float64 `json:"instant_total_current"`
|
||||
IACurrent float64 `json:"i_a_current"`
|
||||
IBCurrent float64 `json:"i_b_current"`
|
||||
ICCurrent float64 `json:"i_c_current"`
|
||||
}
|
||||
|
||||
type teslaBatteryResponse struct {
|
||||
Percentage float64 `json:"percentage"`
|
||||
}
|
||||
|
||||
// Tesla is the tesla powerwall meter
|
||||
type Tesla struct {
|
||||
*request.Helper
|
||||
|
|
@ -93,7 +68,7 @@ func NewTesla(uri, usage, password string) (api.Meter, error) {
|
|||
|
||||
m := &Tesla{
|
||||
Helper: request.NewHelper(log),
|
||||
uri: util.DefaultScheme(uri, "https"),
|
||||
uri: util.DefaultScheme(strings.TrimSuffix(uri, "/"), "https"),
|
||||
usage: strings.ToLower(usage),
|
||||
password: password,
|
||||
}
|
||||
|
|
@ -124,30 +99,26 @@ func NewTesla(uri, usage, password string) (api.Meter, error) {
|
|||
|
||||
// Login calls login and saves the returned cookie
|
||||
func (m *Tesla) Login() error {
|
||||
// username for the powerwall seems to always be customer; email is not required for authentication
|
||||
payload := map[string]interface{}{"password": m.password, "username": "customer"}
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
data := map[string]interface{}{
|
||||
"username": "customer",
|
||||
"password": m.password,
|
||||
}
|
||||
|
||||
// returns cookie which is saved in the cookie jar
|
||||
resp, err := m.Client.Post(m.uri+teslaLoginURI, "application/json", bytes.NewReader(payloadBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
req, err := request.New(http.MethodPost, m.uri+powerwall.LoginURI, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
// use DoBody as it will close the response body
|
||||
if _, err = m.DoBody(req); err != nil {
|
||||
err = fmt.Errorf("login failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if body, err := request.ReadBody(resp); err != nil {
|
||||
return fmt.Errorf("couldn't login: %s: %s", err, string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// CurrentPower implements the Meter.CurrentPower interface
|
||||
func (m *Tesla) CurrentPower() (float64, error) {
|
||||
var res teslaMeterResponse
|
||||
if err := m.GetJSON(m.uri+teslaMeterURI, &res); err != nil {
|
||||
var res powerwall.MeterResponse
|
||||
if err := m.GetJSON(m.uri+powerwall.MeterURI, &res); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
@ -160,8 +131,8 @@ func (m *Tesla) CurrentPower() (float64, error) {
|
|||
|
||||
// totalEnergy implements the api.MeterEnergy interface
|
||||
func (m *Tesla) totalEnergy() (float64, error) {
|
||||
var res teslaMeterResponse
|
||||
if err := m.GetJSON(m.uri+teslaMeterURI, &res); err != nil {
|
||||
var res powerwall.MeterResponse
|
||||
if err := m.GetJSON(m.uri+powerwall.MeterURI, &res); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
@ -179,8 +150,8 @@ func (m *Tesla) totalEnergy() (float64, error) {
|
|||
|
||||
// batterySoC implements the api.Battery interface
|
||||
func (m *Tesla) batterySoC() (float64, error) {
|
||||
var res teslaBatteryResponse
|
||||
err := m.GetJSON(m.uri+teslaBatteryURI, &res)
|
||||
var res powerwall.BatteryResponse
|
||||
err := m.GetJSON(m.uri+powerwall.BatteryURI, &res)
|
||||
|
||||
return res.Percentage, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue