Homewizard: add cache (#9158)
This commit is contained in:
parent
4cc88a0983
commit
0c9dbe0008
3 changed files with 87 additions and 52 deletions
|
|
@ -2,13 +2,11 @@ package charger
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/meter/homewizard"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
)
|
||||
|
||||
// HomeWizard project homepage
|
||||
|
|
@ -26,22 +24,25 @@ func init() {
|
|||
|
||||
// NewHomeWizardFromConfig creates a HomeWizard charger from generic config
|
||||
func NewHomeWizardFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
var cc = struct {
|
||||
cc := struct {
|
||||
embed `mapstructure:",squash"`
|
||||
URI string
|
||||
StandbyPower float64
|
||||
}{}
|
||||
Cache time.Duration
|
||||
}{
|
||||
Cache: time.Second,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewHomeWizard(cc.embed, cc.URI, cc.StandbyPower)
|
||||
return NewHomeWizard(cc.embed, cc.URI, cc.StandbyPower, cc.Cache)
|
||||
}
|
||||
|
||||
// NewHomeWizard creates HomeWizard charger
|
||||
func NewHomeWizard(embed embed, uri string, standbypower float64) (*HomeWizard, error) {
|
||||
conn, err := homewizard.NewConnection(uri)
|
||||
func NewHomeWizard(embed embed, uri string, standbypower float64, cache time.Duration) (*HomeWizard, error) {
|
||||
conn, err := homewizard.NewConnection(uri, cache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -52,7 +53,7 @@ func NewHomeWizard(embed embed, uri string, standbypower float64) (*HomeWizard,
|
|||
|
||||
// Check compatible product type
|
||||
if c.conn.ProductType != "HWE-SKT" {
|
||||
return nil, errors.New("not supported product type: " + c.conn.ProductType)
|
||||
return nil, errors.New("unsupported product type: " + c.conn.ProductType)
|
||||
}
|
||||
|
||||
c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
|
||||
|
|
@ -62,34 +63,12 @@ func NewHomeWizard(embed embed, uri string, standbypower float64) (*HomeWizard,
|
|||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (c *HomeWizard) Enabled() (bool, error) {
|
||||
var res homewizard.StateResponse
|
||||
err := c.conn.GetJSON(fmt.Sprintf("%s/data", c.conn.URI), &res)
|
||||
return res.PowerOn, err
|
||||
return c.conn.Enabled()
|
||||
}
|
||||
|
||||
// Enable implements the api.Charger interface
|
||||
func (c *HomeWizard) Enable(enable bool) error {
|
||||
var res homewizard.StateResponse
|
||||
data := map[string]interface{}{
|
||||
"power_on": enable,
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPut, fmt.Sprintf("%s/state", c.conn.URI), request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.conn.DoJSON(req, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case enable && !res.PowerOn:
|
||||
return errors.New("switchOn failed")
|
||||
case !enable && res.PowerOn:
|
||||
return errors.New("switchOff failed")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return c.conn.Enable(enable)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*HomeWizard)(nil)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package meter
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/meter/homewizard"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -19,19 +21,22 @@ func init() {
|
|||
// NewHomeWizardFromConfig creates a HomeWizard meter from generic config
|
||||
func NewHomeWizardFromConfig(other map[string]interface{}) (api.Meter, error) {
|
||||
cc := struct {
|
||||
URI string
|
||||
}{}
|
||||
URI string
|
||||
Cache time.Duration
|
||||
}{
|
||||
Cache: time.Second,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewHomeWizard(cc.URI)
|
||||
return NewHomeWizard(cc.URI, cc.Cache)
|
||||
}
|
||||
|
||||
// NewHomeWizard creates HomeWizard meter
|
||||
func NewHomeWizard(uri string) (*HomeWizard, error) {
|
||||
conn, err := homewizard.NewConnection(uri)
|
||||
func NewHomeWizard(uri string, cache time.Duration) (*HomeWizard, error) {
|
||||
conn, err := homewizard.NewConnection(uri, cache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -40,7 +45,7 @@ func NewHomeWizard(uri string) (*HomeWizard, error) {
|
|||
conn: conn,
|
||||
}
|
||||
|
||||
return c, err
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var _ api.Meter = (*HomeWizard)(nil)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ package homewizard
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/transport"
|
||||
|
|
@ -13,12 +16,14 @@ import (
|
|||
// Connection is the homewizard connection
|
||||
type Connection struct {
|
||||
*request.Helper
|
||||
URI string
|
||||
uri string
|
||||
ProductType string
|
||||
dataCache provider.Cacheable[DataResponse]
|
||||
stateCache provider.Cacheable[StateResponse]
|
||||
}
|
||||
|
||||
// NewConnection creates a homewizard connection
|
||||
func NewConnection(uri string) (*Connection, error) {
|
||||
func NewConnection(uri string, cache time.Duration) (*Connection, error) {
|
||||
if uri == "" {
|
||||
return nil, errors.New("missing uri")
|
||||
}
|
||||
|
|
@ -26,36 +31,82 @@ func NewConnection(uri string) (*Connection, error) {
|
|||
log := util.NewLogger("homewizard")
|
||||
c := &Connection{
|
||||
Helper: request.NewHelper(log),
|
||||
URI: fmt.Sprintf("%s/api", util.DefaultScheme(strings.TrimRight(uri, "/"), "http")),
|
||||
uri: fmt.Sprintf("%s/api", util.DefaultScheme(strings.TrimRight(uri, "/"), "http")),
|
||||
}
|
||||
|
||||
c.Client.Transport = request.NewTripper(log, transport.Insecure())
|
||||
|
||||
// Check and set API version + product type
|
||||
// check and set API version + product type
|
||||
var res ApiResponse
|
||||
if err := c.GetJSON(c.URI, &res); err != nil {
|
||||
if err := c.GetJSON(c.uri, &res); err != nil {
|
||||
return c, err
|
||||
}
|
||||
if res.ApiVersion != "v1" {
|
||||
return nil, errors.New("not supported api version: " + res.ApiVersion)
|
||||
return nil, errors.New("unsupported api version: " + res.ApiVersion)
|
||||
}
|
||||
|
||||
c.URI = c.URI + "/" + res.ApiVersion
|
||||
c.uri = c.uri + "/" + res.ApiVersion
|
||||
c.ProductType = res.ProductType
|
||||
|
||||
c.dataCache = provider.ResettableCached(func() (DataResponse, error) {
|
||||
var res DataResponse
|
||||
err := c.GetJSON(fmt.Sprintf("%s/data", c.uri), &res)
|
||||
return res, err
|
||||
}, cache)
|
||||
|
||||
c.stateCache = provider.ResettableCached(func() (StateResponse, error) {
|
||||
var res StateResponse
|
||||
err := c.GetJSON(fmt.Sprintf("%s/state", c.uri), &res)
|
||||
return res, err
|
||||
}, cache)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Enable implements the api.Charger interface
|
||||
func (c *Connection) Enable(enable bool) error {
|
||||
var res StateResponse
|
||||
data := map[string]interface{}{
|
||||
"power_on": enable,
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPut, fmt.Sprintf("%s/state", c.uri), request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.DoJSON(req, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
c.stateCache.Reset()
|
||||
c.dataCache.Reset()
|
||||
}
|
||||
|
||||
switch {
|
||||
case enable && !res.PowerOn:
|
||||
return errors.New("switchOn failed")
|
||||
case !enable && res.PowerOn:
|
||||
return errors.New("switchOff failed")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled reads the homewizard switch state true=on/false=off
|
||||
func (c *Connection) Enabled() (bool, error) {
|
||||
res, err := c.stateCache.Get()
|
||||
return res.PowerOn, err
|
||||
}
|
||||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (d *Connection) CurrentPower() (float64, error) {
|
||||
var res DataResponse
|
||||
err := d.GetJSON(fmt.Sprintf("%s/data", d.URI), &res)
|
||||
func (c *Connection) CurrentPower() (float64, error) {
|
||||
res, err := c.dataCache.Get()
|
||||
return res.ActivePowerW, err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (d *Connection) TotalEnergy() (float64, error) {
|
||||
var res DataResponse
|
||||
err := d.GetJSON(fmt.Sprintf("%s/data", d.URI), &res)
|
||||
func (c *Connection) TotalEnergy() (float64, error) {
|
||||
res, err := c.dataCache.Get()
|
||||
return res.TotalPowerImportT1kWh + res.TotalPowerImportT2kWh + res.TotalPowerImportT3kWh + res.TotalPowerImportT4kWh, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue