151 lines
3.3 KiB
Go
151 lines
3.3 KiB
Go
package shelly
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"strings"
|
|
)
|
|
|
|
type Switch struct {
|
|
*Connection
|
|
}
|
|
|
|
func NewSwitch(conn *Connection) *Switch {
|
|
res := &Switch{
|
|
Connection: conn,
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
// CurrentPower implements the api.Meter interface
|
|
func (sh *Switch) CurrentPower() (float64, error) {
|
|
var power float64
|
|
|
|
d := sh.Connection
|
|
switch d.gen {
|
|
case 0, 1:
|
|
var res Gen1StatusResponse
|
|
uri := fmt.Sprintf("%s/status", d.uri)
|
|
if err := d.GetJSON(uri, &res); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch {
|
|
case d.channel < len(res.Meters):
|
|
power = res.Meters[d.channel].Power
|
|
case d.channel < len(res.EMeters):
|
|
power = res.EMeters[d.channel].Power
|
|
default:
|
|
return 0, errors.New("invalid channel, missing power meter")
|
|
}
|
|
|
|
default:
|
|
var res Gen2StatusResponse
|
|
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch d.channel {
|
|
case 1:
|
|
power = res.Switch1.Apower + res.Pm1.Apower
|
|
case 2:
|
|
power = res.Switch2.Apower + res.Pm2.Apower
|
|
default:
|
|
power = res.Switch0.Apower + res.Pm0.Apower
|
|
}
|
|
}
|
|
|
|
// Assure positive power response (Gen 1 EM devices can provide negative values)
|
|
return math.Abs(power), nil
|
|
}
|
|
|
|
// Enabled implements the api.Charger interface
|
|
func (sh *Switch) Enabled() (bool, error) {
|
|
d := sh.Connection
|
|
switch d.gen {
|
|
case 0, 1:
|
|
var res Gen1SwitchResponse
|
|
uri := fmt.Sprintf("%s/relay/%d", d.uri, d.channel)
|
|
err := d.GetJSON(uri, &res)
|
|
return res.Ison, err
|
|
|
|
default:
|
|
var res Gen2SwitchResponse
|
|
err := d.execGen2Cmd("Switch.GetStatus", false, &res)
|
|
return res.Output, err
|
|
}
|
|
}
|
|
|
|
// Enable implements the api.Charger interface
|
|
func (sh *Switch) Enable(enable bool) error {
|
|
var err error
|
|
onoff := map[bool]string{true: "on", false: "off"}
|
|
|
|
d := sh.Connection
|
|
switch d.gen {
|
|
case 0, 1:
|
|
var res Gen1SwitchResponse
|
|
uri := fmt.Sprintf("%s/relay/%d?turn=%s", d.uri, d.channel, onoff[enable])
|
|
err = d.GetJSON(uri, &res)
|
|
|
|
default:
|
|
var res Gen2SwitchResponse
|
|
err = d.execGen2Cmd("Switch.Set", enable, &res)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// TotalEnergy implements the api.Meter interface
|
|
func (sh *Switch) TotalEnergy() (float64, error) {
|
|
var energy float64
|
|
|
|
d := sh.Connection
|
|
switch d.gen {
|
|
case 0, 1:
|
|
var res Gen1StatusResponse
|
|
uri := fmt.Sprintf("%s/status", d.uri)
|
|
if err := d.GetJSON(uri, &res); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch {
|
|
case d.channel < len(res.Meters):
|
|
energy = res.Meters[d.channel].Total
|
|
case d.channel < len(res.EMeters):
|
|
energy = res.EMeters[d.channel].Total
|
|
default:
|
|
return 0, errors.New("invalid channel, missing power meter")
|
|
}
|
|
|
|
energy = gen1Energy(d.devicetype, energy)
|
|
|
|
default:
|
|
var res Gen2StatusResponse
|
|
if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch d.channel {
|
|
case 1:
|
|
energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total
|
|
case 2:
|
|
energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total
|
|
default:
|
|
energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total
|
|
}
|
|
}
|
|
|
|
return energy / 1000, nil
|
|
}
|
|
|
|
// gen1Energy in kWh
|
|
func gen1Energy(devicetype string, energy float64) float64 {
|
|
// Gen 1 Shelly EM devices are providing Watt hours, Gen 1 Shelly PM devices are providing Watt minutes
|
|
if !strings.Contains(devicetype, "EM") {
|
|
energy /= 60
|
|
}
|
|
return energy
|
|
}
|