-
+
[] },
},
@@ -64,13 +63,13 @@ export default {
if (this.vehicleDetectionActive) {
return "refresh";
}
- if (this.connected || this.parked) {
+ if (this.connected) {
return "vehicle";
}
return null;
},
name() {
- if (this.vehiclePresent || this.parked) {
+ if (this.vehiclePresent) {
return this.vehicleTitle || this.$t("main.vehicle.fallbackName");
}
if (this.connected) {
diff --git a/charger/charger.go b/charger/charger.go
index e783125f5..fa6cc1343 100644
--- a/charger/charger.go
+++ b/charger/charger.go
@@ -10,6 +10,7 @@ import (
// Charger is an api.Charger implementation with configurable getters and setters.
type Charger struct {
+ *embed
statusG func() (string, error)
enabledG func() (bool, error)
enableS func(bool) error
@@ -25,9 +26,11 @@ func init() {
// NewConfigurableFromConfig creates a new configurable charger
func NewConfigurableFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
Status, Enable, Enabled, MaxCurrent provider.Config
Identify, Phases1p3p *provider.Config
}
+
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
@@ -54,6 +57,8 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Charger, error
c, err := NewConfigurable(status, enabled, enable, maxcurrent)
+ c.embed = &cc.embed
+
// decorator phases
var phases1p3p func(int) error
if err == nil && cc.Phases1p3p != nil {
@@ -82,6 +87,7 @@ func NewConfigurable(
maxCurrentS func(int64) error,
) (*Charger, error) {
c := &Charger{
+ embed: new(embed),
statusG: statusG,
enabledG: enabledG,
enableS: enableS,
diff --git a/charger/embed.go b/charger/embed.go
new file mode 100644
index 000000000..37832e250
--- /dev/null
+++ b/charger/embed.go
@@ -0,0 +1,24 @@
+package charger
+
+import (
+ "github.com/evcc-io/evcc/api"
+)
+
+type embed struct {
+ Icon_ string `mapstructure:"icon"`
+ Features_ []api.Feature `mapstructure:"features"`
+}
+
+var _ api.IconDescriber = (*embed)(nil)
+
+// Icon implements the api.Vehicle interface
+func (v *embed) Icon() string {
+ return v.Icon_
+}
+
+var _ api.FeatureDescriber = (*embed)(nil)
+
+// Features implements the api.FeatureDescriber interface
+func (v *embed) Features() []api.Feature {
+ return v.Features_
+}
diff --git a/charger/fritzdect.go b/charger/fritzdect.go
index 3dc03c6ce..7ad6468f6 100644
--- a/charger/fritzdect.go
+++ b/charger/fritzdect.go
@@ -25,6 +25,7 @@ func init() {
// NewFritzDECTFromConfig creates a fritzdect charger from generic config
func NewFritzDECTFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
fritzdect.Settings `mapstructure:",squash"`
StandbyPower float64
}
@@ -33,18 +34,18 @@ func NewFritzDECTFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, err
}
- return NewFritzDECT(cc.URI, cc.AIN, cc.User, cc.Password, cc.StandbyPower)
+ return NewFritzDECT(cc.embed, cc.URI, cc.AIN, cc.User, cc.Password, cc.StandbyPower)
}
// NewFritzDECT creates a new connection with standbypower for charger
-func NewFritzDECT(uri, ain, user, password string, standbypower float64) (*FritzDECT, error) {
+func NewFritzDECT(embed embed, uri, ain, user, password string, standbypower float64) (*FritzDECT, error) {
conn, err := fritzdect.NewConnection(uri, ain, user, password)
c := &FritzDECT{
conn: conn,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, err
}
diff --git a/charger/homematic.go b/charger/homematic.go
index 1462a910a..efd57c90f 100644
--- a/charger/homematic.go
+++ b/charger/homematic.go
@@ -19,6 +19,7 @@ func init() {
// NewCCUFromConfig creates a Homematic charger from generic config
func NewCCUFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
URI string
Device string
MeterChannel string
@@ -32,18 +33,18 @@ func NewCCUFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, err
}
- return NewCCU(cc.URI, cc.Device, cc.MeterChannel, cc.SwitchChannel, cc.User, cc.Password, cc.StandbyPower)
+ return NewCCU(cc.embed, cc.URI, cc.Device, cc.MeterChannel, cc.SwitchChannel, cc.User, cc.Password, cc.StandbyPower)
}
// NewCCU creates a new connection with standbypower for charger
-func NewCCU(uri, deviceid, meterid, switchid, user, password string, standbypower float64) (*CCU, error) {
+func NewCCU(embed embed, uri, deviceid, meterid, switchid, user, password string, standbypower float64) (*CCU, error) {
conn, err := homematic.NewConnection(uri, deviceid, meterid, switchid, user, password)
c := &CCU{
conn: conn,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, err
}
diff --git a/charger/mystrom.go b/charger/mystrom.go
index 44439b0ef..3edd4fc34 100644
--- a/charger/mystrom.go
+++ b/charger/mystrom.go
@@ -19,15 +19,15 @@ func init() {
// MyStrom charger implementation
type MyStrom struct {
- conn *mystrom.Connection
*switchSocket
- cache time.Duration
- reportCache provider.Cacheable[mystrom.Report]
+ conn *mystrom.Connection
+ reportG provider.Cacheable[mystrom.Report]
}
// NewMyStromFromConfig creates a myStrom charger from generic config
func NewMyStromFromConfig(other map[string]interface{}) (api.Charger, error) {
cc := struct {
+ embed `mapstructure:",squash"`
URI string
StandbyPower float64
Cache time.Duration
@@ -40,26 +40,24 @@ func NewMyStromFromConfig(other map[string]interface{}) (api.Charger, error) {
}
c := &MyStrom{
- conn: mystrom.NewConnection(cc.URI),
- cache: cc.Cache,
+ conn: mystrom.NewConnection(cc.URI),
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, cc.StandbyPower)
- c.reportCache = provider.ResettableCached(c.conn.Report, c.cache)
+ c.switchSocket = NewSwitchSocket(&cc.embed, c.Enabled, c.conn.CurrentPower, cc.StandbyPower)
+ c.reportG = provider.ResettableCached(c.conn.Report, cc.Cache)
return c, nil
}
// Enabled implements the api.Charger interface
func (c *MyStrom) Enabled() (bool, error) {
- res, err := c.reportCache.Get()
+ res, err := c.reportG.Get()
return res.Relay, err
}
// Enable implements the api.Charger interface
func (c *MyStrom) Enable(enable bool) error {
- // reset cache
- c.reportCache.Reset()
+ c.reportG.Reset()
onoff := map[bool]int{false: 0, true: 1}
return c.conn.Request(fmt.Sprintf("relay?state=%d", onoff[enable]))
diff --git a/charger/shelly.go b/charger/shelly.go
index f987ef4e3..ecc1a7ffc 100644
--- a/charger/shelly.go
+++ b/charger/shelly.go
@@ -21,6 +21,7 @@ func init() {
// NewShellyFromConfig creates a Shelly charger from generic config
func NewShellyFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
URI string
User string
Password string
@@ -32,11 +33,11 @@ func NewShellyFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, err
}
- return NewShelly(cc.URI, cc.User, cc.Password, cc.Channel, cc.StandbyPower)
+ return NewShelly(cc.embed, cc.URI, cc.User, cc.Password, cc.Channel, cc.StandbyPower)
}
// NewShelly creates Shelly charger
-func NewShelly(uri, user, password string, channel int, standbypower float64) (*Shelly, error) {
+func NewShelly(embed embed, uri, user, password string, channel int, standbypower float64) (*Shelly, error) {
conn, err := shelly.NewConnection(uri, user, password, channel)
if err != nil {
return nil, err
@@ -46,7 +47,7 @@ func NewShelly(uri, user, password string, channel int, standbypower float64) (*
conn: conn,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, nil
}
diff --git a/charger/switchsocket.go b/charger/switchsocket.go
index 0bcf76bb2..5a6f1694a 100644
--- a/charger/switchsocket.go
+++ b/charger/switchsocket.go
@@ -5,17 +5,20 @@ import "github.com/evcc-io/evcc/api"
// switchSocket implements the api.Charger Status and CurrentPower methods
// using basic generic switch socket functions
type switchSocket struct {
+ *embed
enabled func() (bool, error)
currentPower func() (float64, error)
standbypower float64
}
func NewSwitchSocket(
+ embed *embed,
enabled func() (bool, error),
currentPower func() (float64, error),
standbypower float64,
) *switchSocket {
return &switchSocket{
+ embed: embed,
enabled: enabled,
currentPower: currentPower,
standbypower: standbypower,
diff --git a/charger/tapo.go b/charger/tapo.go
index d102979da..533a71396 100644
--- a/charger/tapo.go
+++ b/charger/tapo.go
@@ -19,6 +19,7 @@ func init() {
// NewTapoFromConfig creates a Tapo charger from generic config
func NewTapoFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
URI string
User string
Password string
@@ -29,11 +30,11 @@ func NewTapoFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, err
}
- return NewTapo(cc.URI, cc.User, cc.Password, cc.StandbyPower)
+ return NewTapo(cc.embed, cc.URI, cc.User, cc.Password, cc.StandbyPower)
}
// NewTapo creates Tapo charger
-func NewTapo(uri, user, password string, standbypower float64) (*Tapo, error) {
+func NewTapo(embed embed, uri, user, password string, standbypower float64) (*Tapo, error) {
conn, err := tapo.NewConnection(uri, user, password)
if err != nil {
return nil, err
@@ -43,7 +44,7 @@ func NewTapo(uri, user, password string, standbypower float64) (*Tapo, error) {
conn: conn,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, nil
}
diff --git a/charger/tasmota.go b/charger/tasmota.go
index 09c0e8b9c..5cfc3c2d8 100644
--- a/charger/tasmota.go
+++ b/charger/tasmota.go
@@ -29,6 +29,7 @@ func init() {
// NewTasmotaFromConfig creates a Tasmota charger from generic config
func NewTasmotaFromConfig(other map[string]interface{}) (api.Charger, error) {
cc := struct {
+ embed `mapstructure:",squash"`
URI string
User string
Password string
@@ -42,11 +43,11 @@ func NewTasmotaFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, err
}
- return NewTasmota(cc.URI, cc.User, cc.Password, cc.Channel, cc.StandbyPower)
+ return NewTasmota(cc.embed, cc.URI, cc.User, cc.Password, cc.Channel, cc.StandbyPower)
}
// NewTasmota creates Tasmota charger
-func NewTasmota(uri, user, password string, channel int, standbypower float64) (*Tasmota, error) {
+func NewTasmota(embed embed, uri, user, password string, channel int, standbypower float64) (*Tasmota, error) {
conn, err := tasmota.NewConnection(uri, user, password, channel)
if err != nil {
return nil, err
@@ -57,7 +58,7 @@ func NewTasmota(uri, user, password string, channel int, standbypower float64) (
channel: channel,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, c.channelExists(channel)
}
diff --git a/charger/tplink.go b/charger/tplink.go
index dea31efa7..dc6164ad5 100644
--- a/charger/tplink.go
+++ b/charger/tplink.go
@@ -23,6 +23,7 @@ func init() {
// NewTPLinkFromConfig creates a TP-Link charger from generic config
func NewTPLinkFromConfig(other map[string]interface{}) (api.Charger, error) {
var cc struct {
+ embed `mapstructure:",squash"`
URI string
StandbyPower float64
}
@@ -35,11 +36,11 @@ func NewTPLinkFromConfig(other map[string]interface{}) (api.Charger, error) {
return nil, errors.New("missing uri")
}
- return NewTPLink(cc.URI, cc.StandbyPower)
+ return NewTPLink(cc.embed, cc.URI, cc.StandbyPower)
}
// NewTPLink creates TP-Link charger
-func NewTPLink(uri string, standbypower float64) (*TPLink, error) {
+func NewTPLink(embed embed, uri string, standbypower float64) (*TPLink, error) {
conn, err := tplink.NewConnection(uri)
if err != nil {
return nil, err
@@ -49,7 +50,7 @@ func NewTPLink(uri string, standbypower float64) (*TPLink, error) {
conn: conn,
}
- c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, standbypower)
+ c.switchSocket = NewSwitchSocket(&embed, c.Enabled, c.conn.CurrentPower, standbypower)
return c, nil
}
diff --git a/core/const.go b/core/const.go
index 7fd794ba1..0a7592c10 100644
--- a/core/const.go
+++ b/core/const.go
@@ -7,16 +7,17 @@ const (
phasesEnabled = "phasesEnabled" // enabled phases (1/3)
phasesActive = "phasesActive" // active phases as used by vehicle (1/2/3)
- vehicleDetectionActive = "vehicleDetectionActive" // vehicle detection is active (bool)
+ chargerIcon = "chargerIcon" // charger icon for ui
- vehicleOdometer = "vehicleOdometer" // vehicle odometer
- vehicleRange = "vehicleRange" // vehicle range
- vehicleSoc = "vehicleSoc" // vehicle soc
- vehicleTargetSoc = "vehicleTargetSoc" // vehicle soc limit
- vehicleCapacity = "vehicleCapacity" // vehicle battery capacity
- vehicleIcon = "vehicleIcon" // vehicle icon for ui
- vehiclePresent = "vehiclePresent" // vehicle detected
- vehicleTitle = "vehicleTitle" // vehicle title
+ vehicleCapacity = "vehicleCapacity" // vehicle battery capacity
+ vehicleDetectionActive = "vehicleDetectionActive" // vehicle detection active
+ vehicleIcon = "vehicleIcon" // vehicle icon for ui
+ vehicleOdometer = "vehicleOdometer" // vehicle odometer
+ vehiclePresent = "vehiclePresent" // vehicle detected
+ vehicleRange = "vehicleRange" // vehicle range
+ vehicleSoc = "vehicleSoc" // vehicle soc
+ vehicleTargetSoc = "vehicleTargetSoc" // vehicle soc limit
+ vehicleTitle = "vehicleTitle" // vehicle title
minCurrent = "minCurrent" // charger min current
maxCurrent = "maxCurrent" // charger max current
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 93fe25ab8..150062158 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -436,7 +436,9 @@ func (lp *Loadpoint) evVehicleConnectHandler() {
}
// set default or start detection
- lp.vehicleDefaultOrDetect()
+ if !lp.chargerHasFeature(api.IntegratedDevice) {
+ lp.vehicleDefaultOrDetect()
+ }
// immediately allow pv mode activity
lp.elapsePVTimer()
@@ -561,6 +563,18 @@ func (lp *Loadpoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
lp.publishTimer(phaseTimer, 0, timerInactive)
lp.publishTimer(pvTimer, 0, timerInactive)
+ // charger features
+ for _, f := range []api.Feature{api.IntegratedDevice} {
+ lp.publishChargerFeature(f)
+ }
+
+ // charger icon
+ if c, ok := lp.charger.(api.IconDescriber); ok {
+ lp.publish(chargerIcon, c.Icon())
+ } else {
+ lp.publish(chargerIcon, nil)
+ }
+
// assign and publish default vehicle
if lp.defaultVehicle != nil {
lp.setActiveVehicle(lp.defaultVehicle)
@@ -1037,14 +1051,6 @@ func (lp *Loadpoint) pvScalePhases(availablePower, minCurrent, maxCurrent float6
return false
}
-// coordinatedVehicles is the slice of vehicles from the coordinator
-func (lp *Loadpoint) coordinatedVehicles() []api.Vehicle {
- if lp.coordinator == nil {
- return nil
- }
- return lp.coordinator.GetVehicles()
-}
-
// TODO move up to timer functions
func (lp *Loadpoint) publishTimer(name string, delay time.Duration, action string) {
timer := lp.pvTimer
@@ -1335,24 +1341,23 @@ func (lp *Loadpoint) socPollAllowed() bool {
return false
}
-// checks if the connected charger can provide Soc to the connected vehicle
-func (lp *Loadpoint) socProvidedByCharger() bool {
- if charger, ok := lp.charger.(api.Battery); ok {
- if _, err := charger.Soc(); err == nil {
- return true
- }
- }
- return false
-}
-
// publish state of charge, remaining charge duration and range
func (lp *Loadpoint) publishSocAndRange() {
+ soc, err := lp.chargerSoc()
+
// guard for socEstimator removed by api
if lp.socEstimator == nil {
+ // This is a workaround for heaters. Without vehicle, the soc estimator is not initialized.
+ // We need to check if the charger can provide soc and use it if available.
+ if err == nil {
+ lp.vehicleSoc = soc
+ lp.publish(vehicleSoc, lp.vehicleSoc)
+ }
+
return
}
- if lp.socPollAllowed() || lp.socProvidedByCharger() {
+ if err == nil || lp.socPollAllowed() {
lp.socUpdated = lp.clock.Now()
f, err := lp.socEstimator.Soc(lp.getChargedEnergy())
@@ -1366,7 +1371,7 @@ func (lp *Loadpoint) publishSocAndRange() {
return
}
- lp.vehicleSoc = math.Trunc(f)
+ lp.vehicleSoc = f
lp.log.DEBUG.Printf("vehicle soc: %.0f%%", lp.vehicleSoc)
lp.publish(vehicleSoc, lp.vehicleSoc)
@@ -1463,7 +1468,7 @@ func (lp *Loadpoint) Update(sitePower float64, batteryBuffered bool) {
lp.publish("enabled", lp.enabled)
// identify connected vehicle
- if lp.connected() {
+ if lp.connected() && !lp.chargerHasFeature(api.IntegratedDevice) {
// read identity and run associated action
lp.identifyVehicle()
diff --git a/core/loadpoint_charger.go b/core/loadpoint_charger.go
new file mode 100644
index 000000000..607b9e8d7
--- /dev/null
+++ b/core/loadpoint_charger.go
@@ -0,0 +1,32 @@
+package core
+
+import (
+ "github.com/evcc-io/evcc/api"
+ "golang.org/x/exp/slices"
+)
+
+// chargerHasFeature checks availability of charger feature
+func (lp *Loadpoint) chargerHasFeature(f api.Feature) bool {
+ c, ok := lp.charger.(api.FeatureDescriber)
+ if ok {
+ ok = slices.Contains(c.Features(), f)
+ }
+ return ok
+}
+
+// publishChargerFeature publishes availability of charger features
+func (lp *Loadpoint) publishChargerFeature(f api.Feature) {
+ c, ok := lp.charger.(api.FeatureDescriber)
+ if ok {
+ ok = slices.Contains(c.Features(), f)
+ }
+ lp.publish("chargerFeature"+f.String(), ok)
+}
+
+// chargerSoc returns charger soc if available
+func (lp *Loadpoint) chargerSoc() (float64, error) {
+ if c, ok := lp.charger.(api.Battery); ok {
+ return c.Soc()
+ }
+ return 0, api.ErrNotAvailable
+}
diff --git a/core/loadpoint_vehicle.go b/core/loadpoint_vehicle.go
index 0b9bc3d60..cac7d4c95 100644
--- a/core/loadpoint_vehicle.go
+++ b/core/loadpoint_vehicle.go
@@ -9,6 +9,7 @@ import (
"github.com/evcc-io/evcc/core/db"
"github.com/evcc-io/evcc/core/soc"
"github.com/evcc-io/evcc/provider"
+ "golang.org/x/exp/slices"
)
const (
@@ -16,6 +17,14 @@ const (
vehicleDetectDuration = 10 * time.Minute
)
+// coordinatedVehicles is the slice of vehicles from the coordinator
+func (lp *Loadpoint) coordinatedVehicles() []api.Vehicle {
+ if lp.coordinator == nil {
+ return nil
+ }
+ return lp.coordinator.GetVehicles()
+}
+
// setVehicleIdentifier updated the vehicle id as read from the charger
func (lp *Loadpoint) setVehicleIdentifier(id string) {
if lp.vehicleIdentifier != id {
@@ -191,20 +200,20 @@ func (lp *Loadpoint) unpublishVehicle() {
lp.setRemainingEnergy(0)
lp.setRemainingDuration(0)
- lp.vehiclePublishFeature(api.Offline)
+ lp.publishVehicleFeature(api.Offline)
}
// vehicleHasFeature checks availability of vehicle feature
func (lp *Loadpoint) vehicleHasFeature(f api.Feature) bool {
v, ok := lp.vehicle.(api.FeatureDescriber)
if ok {
- ok = v.Has(f)
+ ok = slices.Contains(v.Features(), f)
}
return ok
}
-// vehiclePublishFeature availability of vehicle features
-func (lp *Loadpoint) vehiclePublishFeature(f api.Feature) {
+// publishVehicleFeature availability of vehicle features
+func (lp *Loadpoint) publishVehicleFeature(f api.Feature) {
lp.publish("vehicleFeature"+f.String(), lp.vehicleHasFeature(f))
}
diff --git a/vehicle/embed.go b/vehicle/embed.go
index b573f9508..deff59fbe 100644
--- a/vehicle/embed.go
+++ b/vehicle/embed.go
@@ -2,7 +2,6 @@ package vehicle
import (
"github.com/evcc-io/evcc/api"
- "golang.org/x/exp/slices"
)
type embed struct {
@@ -25,11 +24,6 @@ func (v *embed) SetTitle(title string) {
v.Title_ = title
}
-// Icon implements the api.Vehicle interface
-func (v *embed) Icon() string {
- return v.Icon_
-}
-
// Capacity implements the api.Vehicle interface
func (v *embed) Capacity() float64 {
return v.Capacity_
@@ -50,14 +44,16 @@ func (v *embed) OnIdentified() api.ActionConfig {
return v.OnIdentify
}
+var _ api.IconDescriber = (*embed)(nil)
+
+// Icon implements the api.Vehicle interface
+func (v *embed) Icon() string {
+ return v.Icon_
+}
+
var _ api.FeatureDescriber = (*embed)(nil)
// Features implements the api.FeatureDescriber interface
func (v *embed) Features() []api.Feature {
return v.Features_
}
-
-// Features implements the api.FeatureDescriber interface
-func (v *embed) Has(f api.Feature) bool {
- return slices.Contains(v.Features_, f)
-}
diff --git a/vehicle/wrapper/wrapper.go b/vehicle/wrapper/wrapper.go
index 9ed6a31f1..b6608190f 100644
--- a/vehicle/wrapper/wrapper.go
+++ b/vehicle/wrapper/wrapper.go
@@ -68,11 +68,6 @@ func (v *Wrapper) Features() []api.Feature {
return []api.Feature{api.Offline}
}
-// Features implements the api.FeatureDescriber interface
-func (v *Wrapper) Has(f api.Feature) bool {
- return f == api.Offline
-}
-
var _ api.Battery = (*Wrapper)(nil)
// Soc implements the api.Battery interface