Warp2: support energy manager (BC) (#7995)
This commit is contained in:
parent
cf5394484c
commit
ea6d1601f8
13 changed files with 551 additions and 569 deletions
|
|
@ -41,7 +41,7 @@ func init() {
|
|||
registry.Add("go-e", NewGoEFromConfig)
|
||||
}
|
||||
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateGoE -b *GoE -r api.Charger -t "api.MeterEnergy,func() (float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) (error)"
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateGoE -b *GoE -r api.Charger -t "api.MeterEnergy,func() (float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
|
||||
|
||||
// NewGoEFromConfig creates a go-e charger from generic config
|
||||
func NewGoEFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ func NewOCPPFromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
return decorateOCPP(c, powerG, totalEnergyG, currentsG, phasesS), nil
|
||||
}
|
||||
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateOCPP -b *OCPP -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) (error)"
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateOCPP -b *OCPP -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
|
||||
|
||||
// NewOCPP creates OCPP charger
|
||||
func NewOCPP(id string, connector int, idtag string,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type OpenWB struct {
|
|||
authS func(string) error
|
||||
}
|
||||
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateOpenWB -b *OpenWB -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) (error)" -t "api.Battery,Soc,func() (float64, error)"
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateOpenWB -b *OpenWB -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error" -t "api.Battery,Soc,func() (float64, error)"
|
||||
|
||||
// NewOpenWBFromConfig creates a new configurable charger
|
||||
func NewOpenWBFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
|
|
|
|||
313
charger/warp.go
313
charger/warp.go
|
|
@ -1,313 +0,0 @@
|
|||
package charger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/charger/warp"
|
||||
v1 "github.com/evcc-io/evcc/charger/warp/v1"
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
"github.com/evcc-io/evcc/provider/mqtt"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
// Warp is the Warp charger implementation
|
||||
type Warp struct {
|
||||
log *util.Logger
|
||||
root string
|
||||
client *mqtt.Client
|
||||
enabledG func() (string, error)
|
||||
statusG func() (string, error)
|
||||
meterG func() (string, error)
|
||||
meterDetailsG func() (string, error)
|
||||
enableS func(bool) error
|
||||
maxcurrentS func(int64) error
|
||||
enabled bool // cache
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("warp", NewWarpFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go run ../cmd/tools/decorate.go -f decorateWarp -b *Warp -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)"
|
||||
|
||||
// NewWarpFromConfig creates a new configurable charger
|
||||
func NewWarpFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
cc := struct {
|
||||
mqtt.Config `mapstructure:",squash"`
|
||||
Topic string
|
||||
Timeout time.Duration
|
||||
}{
|
||||
Topic: warp.RootTopic,
|
||||
Timeout: warp.Timeout,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wb, err := NewWarp(cc.Config, cc.Topic, cc.Timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasMeter := wb.hasMeter()
|
||||
|
||||
var currentPower, totalEnergy func() (float64, error)
|
||||
if hasMeter {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
}
|
||||
|
||||
var currents func() (float64, float64, float64, error)
|
||||
if hasMeter && wb.hasCurrents() {
|
||||
currents = wb.currents
|
||||
}
|
||||
|
||||
return decorateWarp(wb, currentPower, totalEnergy, currents), err
|
||||
}
|
||||
|
||||
// NewWarp creates a new configurable charger
|
||||
func NewWarp(mqttconf mqtt.Config, topic string, timeout time.Duration) (*Warp, error) {
|
||||
log := util.NewLogger("warp")
|
||||
|
||||
client, err := mqtt.RegisteredClientOrDefault(log, mqttconf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wb := &Warp{
|
||||
log: log,
|
||||
root: topic,
|
||||
client: client,
|
||||
}
|
||||
|
||||
// timeout handler
|
||||
to := provider.NewTimeoutHandler(provider.NewMqtt(log, client,
|
||||
fmt.Sprintf("%s/evse/state", topic), timeout,
|
||||
).StringGetter())
|
||||
|
||||
stringG := func(topic string) func() (string, error) {
|
||||
g := provider.NewMqtt(log, client, topic, 0).StringGetter()
|
||||
return to.StringGetter(g)
|
||||
}
|
||||
|
||||
wb.enabledG = stringG(fmt.Sprintf("%s/evse/auto_start_charging", topic))
|
||||
wb.statusG = stringG(fmt.Sprintf("%s/evse/state", topic))
|
||||
wb.meterG = stringG(fmt.Sprintf("%s/meter/state", topic))
|
||||
wb.meterDetailsG = stringG(fmt.Sprintf("%s/meter/detailed_values", topic))
|
||||
|
||||
wb.enableS = provider.NewMqtt(log, client,
|
||||
fmt.Sprintf("%s/evse/auto_start_charging_update", topic), 0).
|
||||
WithPayload(`{ "auto_start_charging": ${enable} }`).
|
||||
BoolSetter("enable")
|
||||
|
||||
wb.maxcurrentS = provider.NewMqtt(log, client,
|
||||
fmt.Sprintf("%s/evse/current_limit", topic), 0).
|
||||
WithPayload(`{ "current": ${maxcurrent} }`).
|
||||
IntSetter("maxcurrent")
|
||||
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Warp) hasMeter() bool {
|
||||
topic := fmt.Sprintf("%s/meter/state", wb.root)
|
||||
|
||||
if state, err := provider.NewMqtt(wb.log, wb.client, topic, 0).StringGetter()(); err == nil {
|
||||
var res v1.MeterState
|
||||
if err := json.Unmarshal([]byte(state), &res); err == nil {
|
||||
return res.State == 2 || len(res.PhasesConnected) > 0
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (wb *Warp) hasCurrents() bool {
|
||||
topic := fmt.Sprintf("%s/meter/detailed_values", wb.root)
|
||||
|
||||
if state, err := provider.NewMqtt(wb.log, wb.client, topic, 0).StringGetter()(); err == nil {
|
||||
var res []float64
|
||||
if err := json.Unmarshal([]byte(state), &res); err == nil {
|
||||
return len(res) > 5
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Enable implements the api.Charger interface
|
||||
func (wb *Warp) Enable(enable bool) error {
|
||||
// set auto_start_charging
|
||||
if err := wb.enableS(enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// trigger start/stop
|
||||
action := "stop_charging"
|
||||
if enable {
|
||||
action = "start_charging"
|
||||
}
|
||||
|
||||
topic := fmt.Sprintf("%s/%s/%s", wb.root, "evse", action)
|
||||
|
||||
err := wb.client.Publish(topic, false, "null")
|
||||
if err == nil {
|
||||
wb.enabled = enable
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (wb *Warp) status() (v1.EvseState, error) {
|
||||
var res v1.EvseState
|
||||
|
||||
s, err := wb.statusG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// autostart reads the enabled state from charger
|
||||
// use function instead of jq to honor evse/state updates
|
||||
func (wb *Warp) autostart() (bool, error) {
|
||||
var res struct {
|
||||
AutoStartCharging bool `json:"auto_start_charging"`
|
||||
}
|
||||
|
||||
s, err := wb.enabledG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
}
|
||||
|
||||
return res.AutoStartCharging, err
|
||||
}
|
||||
|
||||
// isEnabled reads enabled status from mqtt
|
||||
func (wb *Warp) isEnabled() (bool, error) {
|
||||
enabled, err := wb.autostart()
|
||||
|
||||
var status v1.EvseState
|
||||
if err == nil {
|
||||
status, err = wb.status()
|
||||
}
|
||||
|
||||
if enabled {
|
||||
// check that charge_release is not blocked
|
||||
enabled = status.ChargeRelease != 2
|
||||
} else {
|
||||
// check that vehicle is really not charging
|
||||
enabled = status.VehicleState == 2
|
||||
}
|
||||
|
||||
return enabled, err
|
||||
}
|
||||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (wb *Warp) Enabled() (bool, error) {
|
||||
enabled, err := wb.isEnabled()
|
||||
|
||||
if err == nil && enabled != wb.enabled {
|
||||
start := time.Now()
|
||||
|
||||
// retry to avoid out of sync errors in case of slow warp updates
|
||||
for time.Since(start) <= 2*time.Second {
|
||||
if enabled, err = wb.isEnabled(); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if enabled == wb.enabled {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
return enabled, err
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
func (wb *Warp) Status() (api.ChargeStatus, error) {
|
||||
var status v1.EvseState
|
||||
|
||||
s, err := wb.statusG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &status)
|
||||
}
|
||||
|
||||
res := api.StatusNone
|
||||
switch status.VehicleState {
|
||||
case 0:
|
||||
res = api.StatusA
|
||||
case 1:
|
||||
res = api.StatusB
|
||||
case 2:
|
||||
res = api.StatusC
|
||||
default:
|
||||
if err == nil {
|
||||
err = fmt.Errorf("invalid status: %d", status.VehicleState)
|
||||
}
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// MaxCurrent implements the api.Charger interface
|
||||
func (wb *Warp) MaxCurrent(current int64) error {
|
||||
return wb.maxcurrentS(1000 * current)
|
||||
}
|
||||
|
||||
var _ api.ChargerEx = (*Warp)(nil)
|
||||
|
||||
// MaxCurrentMillis implements the api.ChargerEx interface
|
||||
func (wb *Warp) MaxCurrentMillis(current float64) error {
|
||||
return wb.maxcurrentS(int64(1000 * current))
|
||||
}
|
||||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (wb *Warp) currentPower() (float64, error) {
|
||||
var res v1.MeterState
|
||||
|
||||
s, err := wb.meterG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
}
|
||||
|
||||
return res.Power, err
|
||||
}
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Warp) totalEnergy() (float64, error) {
|
||||
var res v1.MeterState
|
||||
|
||||
s, err := wb.meterG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
}
|
||||
|
||||
return res.EnergyAbs, err
|
||||
}
|
||||
|
||||
// currents implements the api.MeterCurrrents interface
|
||||
func (wb *Warp) currents() (float64, float64, float64, error) {
|
||||
var res []float64
|
||||
|
||||
s, err := wb.meterDetailsG()
|
||||
if err == nil {
|
||||
if err = json.Unmarshal([]byte(s), &res); err == nil {
|
||||
if len(res) > 5 {
|
||||
return res[3], res[4], res[5], nil
|
||||
}
|
||||
|
||||
err = errors.New("invalid length")
|
||||
}
|
||||
}
|
||||
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
86
charger/warp/externalcontrol_enumer.go
Normal file
86
charger/warp/externalcontrol_enumer.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// Code generated by "enumer -type ExternalControl -trimprefix ExternalControl -transform whitespace"; DO NOT EDIT.
|
||||
|
||||
package warp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const _ExternalControlName = "availabledeactivatedruntime conditions not metcurrently switching"
|
||||
|
||||
var _ExternalControlIndex = [...]uint8{0, 9, 20, 46, 65}
|
||||
|
||||
const _ExternalControlLowerName = "availabledeactivatedruntime conditions not metcurrently switching"
|
||||
|
||||
func (i ExternalControl) String() string {
|
||||
if i < 0 || i >= ExternalControl(len(_ExternalControlIndex)-1) {
|
||||
return fmt.Sprintf("ExternalControl(%d)", i)
|
||||
}
|
||||
return _ExternalControlName[_ExternalControlIndex[i]:_ExternalControlIndex[i+1]]
|
||||
}
|
||||
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
func _ExternalControlNoOp() {
|
||||
var x [1]struct{}
|
||||
_ = x[ExternalControlAvailable-(0)]
|
||||
_ = x[ExternalControlDeactivated-(1)]
|
||||
_ = x[ExternalControlRuntimeConditionsNotMet-(2)]
|
||||
_ = x[ExternalControlCurrentlySwitching-(3)]
|
||||
}
|
||||
|
||||
var _ExternalControlValues = []ExternalControl{ExternalControlAvailable, ExternalControlDeactivated, ExternalControlRuntimeConditionsNotMet, ExternalControlCurrentlySwitching}
|
||||
|
||||
var _ExternalControlNameToValueMap = map[string]ExternalControl{
|
||||
_ExternalControlName[0:9]: ExternalControlAvailable,
|
||||
_ExternalControlLowerName[0:9]: ExternalControlAvailable,
|
||||
_ExternalControlName[9:20]: ExternalControlDeactivated,
|
||||
_ExternalControlLowerName[9:20]: ExternalControlDeactivated,
|
||||
_ExternalControlName[20:46]: ExternalControlRuntimeConditionsNotMet,
|
||||
_ExternalControlLowerName[20:46]: ExternalControlRuntimeConditionsNotMet,
|
||||
_ExternalControlName[46:65]: ExternalControlCurrentlySwitching,
|
||||
_ExternalControlLowerName[46:65]: ExternalControlCurrentlySwitching,
|
||||
}
|
||||
|
||||
var _ExternalControlNames = []string{
|
||||
_ExternalControlName[0:9],
|
||||
_ExternalControlName[9:20],
|
||||
_ExternalControlName[20:46],
|
||||
_ExternalControlName[46:65],
|
||||
}
|
||||
|
||||
// ExternalControlString retrieves an enum value from the enum constants string name.
|
||||
// Throws an error if the param is not part of the enum.
|
||||
func ExternalControlString(s string) (ExternalControl, error) {
|
||||
if val, ok := _ExternalControlNameToValueMap[s]; ok {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
if val, ok := _ExternalControlNameToValueMap[strings.ToLower(s)]; ok {
|
||||
return val, nil
|
||||
}
|
||||
return 0, fmt.Errorf("%s does not belong to ExternalControl values", s)
|
||||
}
|
||||
|
||||
// ExternalControlValues returns all values of the enum
|
||||
func ExternalControlValues() []ExternalControl {
|
||||
return _ExternalControlValues
|
||||
}
|
||||
|
||||
// ExternalControlStrings returns a slice of all String values of the enum
|
||||
func ExternalControlStrings() []string {
|
||||
strs := make([]string, len(_ExternalControlNames))
|
||||
copy(strs, _ExternalControlNames)
|
||||
return strs
|
||||
}
|
||||
|
||||
// IsAExternalControl returns "true" if the value is listed in the enum definition. "false" otherwise
|
||||
func (i ExternalControl) IsAExternalControl() bool {
|
||||
for _, v := range _ExternalControlValues {
|
||||
if i == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package v2
|
||||
package warp
|
||||
|
||||
const (
|
||||
FeatureMeter = "meter"
|
||||
|
|
@ -80,3 +80,27 @@ type LastNfcTag struct {
|
|||
Type int `json:"tag_type"`
|
||||
ID string `json:"tag_id"`
|
||||
}
|
||||
|
||||
type EmConfig struct {
|
||||
ContactorInstalled bool `json:"contactor_installed"`
|
||||
PhaseSwitchingMode int `json:"phase_switching_mode"`
|
||||
}
|
||||
|
||||
//go:generate enumer -type ExternalControl -trimprefix ExternalControl -transform whitespace
|
||||
type ExternalControl int
|
||||
|
||||
const (
|
||||
ExternalControlAvailable ExternalControl = iota
|
||||
ExternalControlDeactivated
|
||||
ExternalControlRuntimeConditionsNotMet
|
||||
ExternalControlCurrentlySwitching
|
||||
)
|
||||
|
||||
type EmState struct {
|
||||
ExternalControl ExternalControl `json:"external_control"`
|
||||
PhasesSwitched int `json:"phases_switched"`
|
||||
Input3State bool `json:"input3_state"`
|
||||
Input4State bool `json:"input4_state"`
|
||||
RelayState bool `json:"relay_state"`
|
||||
ErrorFlags int `json:"error_flags"`
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package v1
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
RootTopic = "warp"
|
||||
Timeout = 30 * time.Second
|
||||
|
||||
FeatureMeter = "meter"
|
||||
FeatureMeterPhases = "meter_phases"
|
||||
FeatureNfc = "nfc"
|
||||
)
|
||||
|
||||
// https://www.warp-charger.com/api.html#evse_state
|
||||
type EvseState struct {
|
||||
Iec61851State int `json:"iec61851_state"`
|
||||
VehicleState int `json:"vehicle_state"`
|
||||
ChargeRelease int `json:"charge_release"`
|
||||
ContactorState int `json:"contactor_state"`
|
||||
ContactorError int `json:"contactor_error"`
|
||||
AllowedChargingCurrent int64 `json:"allowed_charging_current"`
|
||||
ErrorState int `json:"error_state"`
|
||||
LockState int `json:"lock_state"`
|
||||
TimeSinceStateChange int64 `json:"time_since_state_change"`
|
||||
Uptime int64 `json:"uptime"`
|
||||
}
|
||||
|
||||
// https://www.warp-charger.com/api.html#evse_low_level_state
|
||||
type LowLevelState struct {
|
||||
LedState int `json:"led_state"`
|
||||
CpPwmDutyCycle int `json:"cp_pwm_duty_cycle"`
|
||||
AdcValues []int `json:"adc_values"`
|
||||
Voltages []int
|
||||
Resistances []int
|
||||
Gpio []bool
|
||||
}
|
||||
|
||||
// https://www.warp-charger.com/api.html#meter_state
|
||||
type MeterState struct {
|
||||
State int `json:"state"` // Warp 1 only
|
||||
Power float64 `json:"power"`
|
||||
EnergyRel float64 `json:"energy_rel"`
|
||||
EnergyAbs float64 `json:"energy_abs"`
|
||||
PhasesActive []bool `json:"phases_active"`
|
||||
PhasesConnected []bool `json:"phases_connected"`
|
||||
}
|
||||
129
charger/warp2.go
129
charger/warp2.go
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/charger/warp"
|
||||
v2 "github.com/evcc-io/evcc/charger/warp/v2"
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
"github.com/evcc-io/evcc/provider/mqtt"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -18,7 +17,6 @@ import (
|
|||
// Warp2 is the Warp charger v2 firmware implementation
|
||||
type Warp2 struct {
|
||||
log *util.Logger
|
||||
root string
|
||||
client *mqtt.Client
|
||||
features []string
|
||||
maxcurrentG func() (string, error)
|
||||
|
|
@ -28,21 +26,26 @@ type Warp2 struct {
|
|||
chargeG func() (string, error)
|
||||
userconfigG func() (string, error)
|
||||
maxcurrentS func(int64) error
|
||||
current int64
|
||||
// emConfigG func() (string, error)
|
||||
emStateG func() (string, error)
|
||||
phasesS func(int64) error
|
||||
current int64
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("warp-fw2", NewWarp2FromConfig)
|
||||
registry.Add("warp2", NewWarp2FromConfig)
|
||||
registry.Add("warp-fw2", NewWarp2FromConfig) // deprecated
|
||||
}
|
||||
|
||||
//go:generate go run ../cmd/tools/decorate.go -f decorateWarp2 -b *Warp2 -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.Identifier,Identify,func() (string, error)"
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateWarp2 -b *Warp2 -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.Identifier,Identify,func() (string, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
|
||||
|
||||
// NewWarpFromConfig creates a new configurable charger
|
||||
func NewWarp2FromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
cc := struct {
|
||||
mqtt.Config `mapstructure:",squash"`
|
||||
Topic string
|
||||
Timeout time.Duration
|
||||
mqtt.Config `mapstructure:",squash"`
|
||||
Topic string
|
||||
EnergyManager string
|
||||
Timeout time.Duration
|
||||
}{
|
||||
Topic: warp.RootTopic,
|
||||
Timeout: warp.Timeout,
|
||||
|
|
@ -52,32 +55,39 @@ func NewWarp2FromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
wb, err := NewWarp2(cc.Config, cc.Topic, cc.Timeout)
|
||||
wb, err := NewWarp2(cc.Config, cc.Topic, cc.EnergyManager, cc.Timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currentPower, totalEnergy func() (float64, error)
|
||||
if wb.hasFeature(v2.FeatureMeter) {
|
||||
if wb.hasFeature(cc.Topic, warp.FeatureMeter) {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
}
|
||||
|
||||
var currents func() (float64, float64, float64, error)
|
||||
if wb.hasFeature(v2.FeatureMeterPhases) {
|
||||
if wb.hasFeature(cc.Topic, warp.FeatureMeterPhases) {
|
||||
currents = wb.currents
|
||||
}
|
||||
|
||||
var identity func() (string, error)
|
||||
if wb.hasFeature(v2.FeatureNfc) {
|
||||
if wb.hasFeature(cc.Topic, warp.FeatureNfc) {
|
||||
identity = wb.identify
|
||||
}
|
||||
|
||||
return decorateWarp2(wb, currentPower, totalEnergy, currents, identity), err
|
||||
var phases func(int) error
|
||||
if cc.EnergyManager != "" {
|
||||
if res, err := wb.emState(); err == nil && res.ExternalControl != 1 {
|
||||
phases = wb.phases1p3p
|
||||
}
|
||||
}
|
||||
|
||||
return decorateWarp2(wb, currentPower, totalEnergy, currents, identity, phases), err
|
||||
}
|
||||
|
||||
// NewWarp2 creates a new configurable charger
|
||||
func NewWarp2(mqttconf mqtt.Config, topic string, timeout time.Duration) (*Warp2, error) {
|
||||
func NewWarp2(mqttconf mqtt.Config, topic, emTopic string, timeout time.Duration) (*Warp2, error) {
|
||||
log := util.NewLogger("warp")
|
||||
|
||||
client, err := mqtt.RegisteredClientOrDefault(log, mqttconf)
|
||||
|
|
@ -87,7 +97,6 @@ func NewWarp2(mqttconf mqtt.Config, topic string, timeout time.Duration) (*Warp2
|
|||
|
||||
wb := &Warp2{
|
||||
log: log,
|
||||
root: topic,
|
||||
client: client,
|
||||
current: 6000, // mA
|
||||
}
|
||||
|
|
@ -114,15 +123,22 @@ func NewWarp2(mqttconf mqtt.Config, topic string, timeout time.Duration) (*Warp2
|
|||
WithPayload(`{ "current": ${maxcurrent} }`).
|
||||
IntSetter("maxcurrent")
|
||||
|
||||
// wb.emConfigG = stringG(fmt.Sprintf("%s/energy_manager/config", emTopic))
|
||||
wb.emStateG = stringG(fmt.Sprintf("%s/energy_manager/state", emTopic))
|
||||
wb.phasesS = provider.NewMqtt(log, client,
|
||||
fmt.Sprintf("%s/energy_manager/external_control_update", emTopic), 0).
|
||||
WithPayload(`{ "phases_wanted": ${phases} }`).
|
||||
IntSetter("phases")
|
||||
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Warp2) hasFeature(feature string) bool {
|
||||
func (wb *Warp2) hasFeature(root, feature string) bool {
|
||||
if wb.features != nil {
|
||||
return slices.Contains(wb.features, feature)
|
||||
}
|
||||
|
||||
topic := fmt.Sprintf("%s/info/features", wb.root)
|
||||
topic := fmt.Sprintf("%s/info/features", root)
|
||||
|
||||
if data, err := provider.NewMqtt(wb.log, wb.client, topic, 0).StringGetter()(); err == nil {
|
||||
if err := json.Unmarshal([]byte(data), &wb.features); err == nil {
|
||||
|
|
@ -144,7 +160,7 @@ func (wb *Warp2) Enable(enable bool) error {
|
|||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (wb *Warp2) Enabled() (bool, error) {
|
||||
var res v2.EvseExternalCurrent
|
||||
var res warp.EvseExternalCurrent
|
||||
|
||||
s, err := wb.maxcurrentG()
|
||||
if err == nil {
|
||||
|
|
@ -156,14 +172,18 @@ func (wb *Warp2) Enabled() (bool, error) {
|
|||
|
||||
// Status implements the api.Charger interface
|
||||
func (wb *Warp2) Status() (api.ChargeStatus, error) {
|
||||
var status v2.EvseState
|
||||
res := api.StatusNone
|
||||
|
||||
s, err := wb.statusG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &status)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
var status warp.EvseState
|
||||
if err := json.Unmarshal([]byte(s), &status); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
res := api.StatusNone
|
||||
switch status.Iec61851State {
|
||||
case 0:
|
||||
res = api.StatusA
|
||||
|
|
@ -172,9 +192,7 @@ func (wb *Warp2) Status() (api.ChargeStatus, error) {
|
|||
case 2:
|
||||
res = api.StatusC
|
||||
default:
|
||||
if err == nil {
|
||||
err = fmt.Errorf("invalid status: %d", status.Iec61851State)
|
||||
}
|
||||
err = fmt.Errorf("invalid status: %d", status.Iec61851State)
|
||||
}
|
||||
|
||||
return res, err
|
||||
|
|
@ -203,7 +221,7 @@ func (wb *Warp2) MaxCurrentMillis(current float64) error {
|
|||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (wb *Warp2) currentPower() (float64, error) {
|
||||
var res v2.MeterValues
|
||||
var res warp.MeterValues
|
||||
|
||||
s, err := wb.meterG()
|
||||
if err == nil {
|
||||
|
|
@ -215,7 +233,7 @@ func (wb *Warp2) currentPower() (float64, error) {
|
|||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (wb *Warp2) totalEnergy() (float64, error) {
|
||||
var res v2.MeterValues
|
||||
var res warp.MeterValues
|
||||
|
||||
s, err := wb.meterG()
|
||||
if err == nil {
|
||||
|
|
@ -230,21 +248,23 @@ func (wb *Warp2) currents() (float64, float64, float64, error) {
|
|||
var res []float64
|
||||
|
||||
s, err := wb.meterDetailsG()
|
||||
if err == nil {
|
||||
if err = json.Unmarshal([]byte(s), &res); err == nil {
|
||||
if len(res) > 5 {
|
||||
return res[3], res[4], res[5], nil
|
||||
}
|
||||
|
||||
err = errors.New("invalid length")
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
return 0, 0, 0, err
|
||||
if err := json.Unmarshal([]byte(s), &res); err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
if len(res) <= 5 {
|
||||
return 0, 0, 0, errors.New("invalid length")
|
||||
}
|
||||
|
||||
return res[3], res[4], res[5], nil
|
||||
}
|
||||
|
||||
func (wb *Warp2) identify() (string, error) {
|
||||
var res v2.ChargeTrackerCurrentCharge
|
||||
var res warp.ChargeTrackerCurrentCharge
|
||||
|
||||
s, err := wb.chargeG()
|
||||
if err == nil {
|
||||
|
|
@ -253,3 +273,38 @@ func (wb *Warp2) identify() (string, error) {
|
|||
|
||||
return res.AuthorizationInfo.TagId, err
|
||||
}
|
||||
|
||||
// func (wb *Warp2) emConfig() (warp.EmConfig, error) {
|
||||
// var res warp.EmConfig
|
||||
|
||||
// s, err := wb.emConfigG()
|
||||
// if err == nil {
|
||||
// err = json.Unmarshal([]byte(s), &res)
|
||||
// }
|
||||
|
||||
// return res, err
|
||||
// }
|
||||
|
||||
func (wb *Warp2) emState() (warp.EmState, error) {
|
||||
var res warp.EmState
|
||||
|
||||
s, err := wb.emStateG()
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (wb *Warp2) phases1p3p(phases int) error {
|
||||
res, err := wb.emState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.ExternalControl > 0 {
|
||||
return fmt.Errorf("external control not available: %s", res.ExternalControl.String())
|
||||
}
|
||||
|
||||
return wb.phasesS(int64(phases))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import (
|
|||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), identifier func() (string, error)) api.Charger {
|
||||
func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), identifier func() (string, error), phaseSwitcher func(int) error) api.Charger {
|
||||
switch {
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return base
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
|
|
@ -22,7 +22,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.MeterEnergy
|
||||
|
|
@ -33,7 +33,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
|
|
@ -48,7 +48,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.PhaseCurrents
|
||||
|
|
@ -59,7 +59,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
|
|
@ -74,7 +74,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.MeterEnergy
|
||||
|
|
@ -89,7 +89,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
|
|
@ -108,7 +108,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -119,7 +119,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -134,7 +134,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -149,7 +149,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -168,7 +168,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -183,7 +183,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -202,7 +202,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -221,7 +221,7 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
|
|
@ -243,6 +243,310 @@ func decorateWarp2(base *Warp2, meter func() (float64, error), meterEnergy func(
|
|||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.MeterEnergy
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter == nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.Meter
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.MeterEnergy
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.Meter
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter == nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
|
||||
case identifier != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Warp2
|
||||
api.Identifier
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Warp2: base,
|
||||
Identifier: &decorateWarp2IdentifierImpl{
|
||||
identifier: identifier,
|
||||
},
|
||||
Meter: &decorateWarp2MeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarp2MeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarp2PhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
PhaseSwitcher: &decorateWarp2PhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -279,3 +583,11 @@ type decorateWarp2PhaseCurrentsImpl struct {
|
|||
func (impl *decorateWarp2PhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateWarp2PhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateWarp2PhaseSwitcherImpl) Phases1p3p(phases int) error {
|
||||
return impl.phaseSwitcher(phases)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateWarp(base *Warp, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error)) api.Charger {
|
||||
switch {
|
||||
case meter == nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
return base
|
||||
|
||||
case meter != nil && meterEnergy == nil && phaseCurrents == nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.Meter
|
||||
}{
|
||||
Warp: base,
|
||||
Meter: &decorateWarpMeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
}
|
||||
|
||||
case meter == nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.MeterEnergy
|
||||
}{
|
||||
Warp: base,
|
||||
MeterEnergy: &decorateWarpMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
}
|
||||
|
||||
case meter != nil && meterEnergy != nil && phaseCurrents == nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
}{
|
||||
Warp: base,
|
||||
Meter: &decorateWarpMeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarpMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
}
|
||||
|
||||
case meter == nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.PhaseCurrents
|
||||
}{
|
||||
Warp: base,
|
||||
PhaseCurrents: &decorateWarpPhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
}
|
||||
|
||||
case meter != nil && meterEnergy == nil && phaseCurrents != nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.Meter
|
||||
api.PhaseCurrents
|
||||
}{
|
||||
Warp: base,
|
||||
Meter: &decorateWarpMeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
PhaseCurrents: &decorateWarpPhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
}
|
||||
|
||||
case meter == nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
}{
|
||||
Warp: base,
|
||||
MeterEnergy: &decorateWarpMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarpPhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
}
|
||||
|
||||
case meter != nil && meterEnergy != nil && phaseCurrents != nil:
|
||||
return &struct {
|
||||
*Warp
|
||||
api.Meter
|
||||
api.MeterEnergy
|
||||
api.PhaseCurrents
|
||||
}{
|
||||
Warp: base,
|
||||
Meter: &decorateWarpMeterImpl{
|
||||
meter: meter,
|
||||
},
|
||||
MeterEnergy: &decorateWarpMeterEnergyImpl{
|
||||
meterEnergy: meterEnergy,
|
||||
},
|
||||
PhaseCurrents: &decorateWarpPhaseCurrentsImpl{
|
||||
phaseCurrents: phaseCurrents,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type decorateWarpMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateWarpMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateWarpPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
|
@ -11,20 +11,21 @@ products:
|
|||
capabilities: ["mA"]
|
||||
requirements:
|
||||
description:
|
||||
en: An MQTT broker is required. The charger must be have a configured MQTT connection.
|
||||
de: Es muss ein MQTT Broker installiert sein. Die MQTT Verbindung muss in der Wallbox eingerichtet sein.
|
||||
en: Firmware v2 required.
|
||||
de: Firmware v2 erforderlich.
|
||||
uri: https://docs.evcc.io/docs/devices/chargers#tinkerforge
|
||||
params:
|
||||
- name: fw2
|
||||
required: true
|
||||
type: bool
|
||||
help:
|
||||
de: Firmware v2 installiert
|
||||
en: Firmware v2 installed
|
||||
- preset: mqtt
|
||||
- name: topic
|
||||
default: warp
|
||||
- name: energymanager
|
||||
help:
|
||||
de: EnergyManager MQTT Topic (falls installiert)
|
||||
en: EnergyManager MQTT topic if installed
|
||||
render: |
|
||||
type: {{ if eq .fw2 "true" -}} warp-fw2 {{ else -}} warp {{ end }}
|
||||
type: warp2
|
||||
{{ include "mqtt" . }}
|
||||
topic: {{ .topic }}
|
||||
{{- if .energymanager }}
|
||||
energymanager: {{ .energymanager }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@ product:
|
|||
description: WARP Charger Smart
|
||||
capabilities: ["mA"]
|
||||
description: |
|
||||
Es muss ein MQTT Broker installiert sein. Die MQTT Verbindung muss in der Wallbox eingerichtet sein.
|
||||
Firmware v2 erforderlich.
|
||||
render:
|
||||
- default: |
|
||||
type: template
|
||||
template: tinkerforge-warp
|
||||
fw2: # Firmware v2 installiert
|
||||
host: 192.0.2.2 # IP Adresse oder der Hostname des MQTT Brokers
|
||||
port: 1883 # MQTT Broker Port (Optional)
|
||||
topic: warp # Topic (ohne / am Anfang) (Optional)
|
||||
energymanager: # EnergyManager MQTT Topic (falls installiert) (Optional)
|
||||
advanced: |
|
||||
type: template
|
||||
template: tinkerforge-warp
|
||||
fw2: # Firmware v2 installiert
|
||||
host: 192.0.2.2 # IP Adresse oder der Hostname des MQTT Brokers
|
||||
port: 1883 # MQTT Broker Port (Optional)
|
||||
user: # Benutzerkonto (bspw. E-Mail Adresse, User Id, etc.) (Optional)
|
||||
password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) (Optional)
|
||||
topic: warp # Topic (ohne / am Anfang) (Optional)
|
||||
timeout: 30s # Akzeptiere keine Daten die älter sind als dieser Wert (Optional)
|
||||
energymanager: # EnergyManager MQTT Topic (falls installiert) (Optional)
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@ product:
|
|||
description: WARP Charger Pro
|
||||
capabilities: ["mA"]
|
||||
description: |
|
||||
Es muss ein MQTT Broker installiert sein. Die MQTT Verbindung muss in der Wallbox eingerichtet sein.
|
||||
Firmware v2 erforderlich.
|
||||
render:
|
||||
- default: |
|
||||
type: template
|
||||
template: tinkerforge-warp
|
||||
fw2: # Firmware v2 installiert
|
||||
host: 192.0.2.2 # IP Adresse oder der Hostname des MQTT Brokers
|
||||
port: 1883 # MQTT Broker Port (Optional)
|
||||
topic: warp # Topic (ohne / am Anfang) (Optional)
|
||||
energymanager: # EnergyManager MQTT Topic (falls installiert) (Optional)
|
||||
advanced: |
|
||||
type: template
|
||||
template: tinkerforge-warp
|
||||
fw2: # Firmware v2 installiert
|
||||
host: 192.0.2.2 # IP Adresse oder der Hostname des MQTT Brokers
|
||||
port: 1883 # MQTT Broker Port (Optional)
|
||||
user: # Benutzerkonto (bspw. E-Mail Adresse, User Id, etc.) (Optional)
|
||||
password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) (Optional)
|
||||
topic: warp # Topic (ohne / am Anfang) (Optional)
|
||||
timeout: 30s # Akzeptiere keine Daten die älter sind als dieser Wert (Optional)
|
||||
energymanager: # EnergyManager MQTT Topic (falls installiert) (Optional)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue