evcc-io/meter/tapo/connection.go

95 lines
2.2 KiB
Go

package tapo
import (
"fmt"
"strings"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/insomniacslk/tapo"
)
// Connection is the Tapo connection
type Connection struct {
log *util.Logger
plug tapo.Plug
lasttodayenergy int64
energy int64
}
// NewConnection creates a new Tapo device connection.
// User is encoded by using MessageDigest of SHA1 which is afterwards B64 encoded.
// Password is directly B64 encoded.
func NewConnection(host, user, password string) (*Connection, error) {
if host == "" {
return nil, fmt.Errorf("missing host")
}
if user == "" || password == "" {
return nil, api.ErrMissingCredentials
}
log := util.NewLogger("tapo").Redact(user, password)
plug := tapo.NewPlug(host, nil)
if err := plug.Handshake(user, password); err != nil {
return nil, fmt.Errorf("login failed: %w", err)
}
conn := &Connection{
log: log,
plug: *plug,
}
res, err := conn.plug.GetDeviceInfo()
if err != nil {
return nil, err
}
conn.log.DEBUG.Printf("%s %s connected (fw:%s,hw:%s,mac:%s)", res.Type, res.Model, res.FWVersion, res.HWVersion, res.MAC)
return conn, nil
}
// Enable implements the api.Charger interface
func (c *Connection) Enable(enable bool) error {
return c.plug.SetDeviceInfo(enable)
}
// Enabled implements the api.Charger interface
func (c *Connection) Enabled() (bool, error) {
return c.plug.IsOn()
}
// CurrentPower provides current power consuption
func (c *Connection) CurrentPower() (float64, error) {
resp, err := c.plug.GetEnergyUsage()
if err != nil {
return 0, c.checkMeterError(err)
}
return float64(resp.CurrentPower) / 1e3, nil
}
// ChargedEnergy collects the daily charged energy
func (c *Connection) ChargedEnergy() (float64, error) {
resp, err := c.plug.GetEnergyUsage()
if err != nil {
return 0, c.checkMeterError(err)
}
if int64(resp.TodayEnergy) > c.lasttodayenergy {
c.energy += (int64(resp.TodayEnergy) - c.lasttodayenergy)
}
c.lasttodayenergy = int64(resp.TodayEnergy)
return float64(c.energy) / 1000, nil
}
// checkMeterError checks for missing meter error
func (c *Connection) checkMeterError(err error) error {
if strings.Contains(err.Error(), "-1001") {
return nil
}
return err
}