Skip to content

Commit

Permalink
Add EEBus HEMS for SteuVE (#14950)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Jul 27, 2024
1 parent f9501e5 commit 6c3ecdb
Show file tree
Hide file tree
Showing 16 changed files with 625 additions and 29 deletions.
1 change: 1 addition & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ type Circuit interface {
SetTitle(string)
GetParent() Circuit
RegisterChild(child Circuit)
Wrap(parent Circuit) error
HasMeter() bool
GetMaxPower() float64
GetMaxCurrent() float64
Expand Down
14 changes: 14 additions & 0 deletions api/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/evcc-io/evcc/charger"
"github.com/evcc-io/evcc/cmd/shutdown"
"github.com/evcc-io/evcc/core"
"github.com/evcc-io/evcc/core/circuit"
"github.com/evcc-io/evcc/core/keys"
"github.com/evcc-io/evcc/hems"
"github.com/evcc-io/evcc/meter"
Expand Down Expand Up @@ -160,7 +161,7 @@ NEXT:
}

log := util.NewLogger("circuit-" + cc.Name)
instance, err := core.NewCircuitFromConfig(log, cc.Other)
instance, err := circuit.NewFromConfig(log, cc.Other)
if err != nil {
return fmt.Errorf("cannot create circuit '%s': %w", cc.Name, err)
}
Expand Down
28 changes: 19 additions & 9 deletions core/circuit.go → core/circuit/circuit.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core
package circuit

import (
"fmt"
Expand Down Expand Up @@ -34,8 +34,8 @@ type Circuit struct {
powerUpdated time.Time
}

// NewCircuitFromConfig creates a new Circuit
func NewCircuitFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, error) {
// NewFromConfig creates a new Circuit
func NewFromConfig(log *util.Logger, other map[string]interface{}) (api.Circuit, error) {
cc := struct {
Title string `mapstructure:"title"` // title
ParentRef string `mapstructure:"parent"` // parent circuit reference
Expand All @@ -60,7 +60,7 @@ func NewCircuitFromConfig(log *util.Logger, other map[string]interface{}) (api.C
meter = dev.Instance()
}

circuit, err := NewCircuit(log, cc.Title, cc.MaxCurrent, cc.MaxPower, meter, cc.Timeout)
circuit, err := New(log, cc.Title, cc.MaxCurrent, cc.MaxPower, meter, cc.Timeout)
if err != nil {
return nil, err
}
Expand All @@ -70,14 +70,14 @@ func NewCircuitFromConfig(log *util.Logger, other map[string]interface{}) (api.C
if err != nil {
return nil, err
}
circuit.SetParent(dev.Instance())
circuit.setParent(dev.Instance())
}

return circuit, err
}

// NewCircuit creates a circuit
func NewCircuit(log *util.Logger, title string, maxCurrent, maxPower float64, meter api.Meter, timeout time.Duration) (*Circuit, error) {
// New creates a circuit
func New(log *util.Logger, title string, maxCurrent, maxPower float64, meter api.Meter, timeout time.Duration) (*Circuit, error) {
c := &Circuit{
log: log,
title: title,
Expand Down Expand Up @@ -119,14 +119,24 @@ func (c *Circuit) GetParent() api.Circuit {
return c.parent
}

// SetParent set parent circuit
func (c *Circuit) SetParent(parent api.Circuit) {
// setParent set parent circuit
func (c *Circuit) setParent(parent api.Circuit) error {
c.mu.Lock()
defer c.mu.Unlock()
if c.parent != nil {
return fmt.Errorf("circuit already has a parent")
}
c.parent = parent
if parent != nil {
parent.RegisterChild(c)
}
return nil
}

// Wrap wraps circuit with parent, keeping the original meter
func (c *Circuit) Wrap(parent api.Circuit) error {
parent.(*Circuit).meter = c.meter
return c.setParent(parent)
}

// HasMeter returns the max power setting
Expand Down
6 changes: 3 additions & 3 deletions core/circuit_test.go → core/circuit/circuit_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core
package circuit

import (
"testing"
Expand Down Expand Up @@ -61,7 +61,7 @@ func TestCircuitPower(t *testing.T) {

circ := func(t *testing.T, ctrl *gomock.Controller, maxP float64) (*Circuit, *api.MockMeter) {
m := api.NewMockMeter(ctrl)
c, err := NewCircuit(log, "foo", 0, maxP, m, 0)
c, err := New(log, "foo", 0, maxP, m, 0)
require.NoError(t, err)
return c, m
}
Expand Down Expand Up @@ -100,7 +100,7 @@ func TestCircuitCurrents(t *testing.T) {
api.NewMockMeter(ctrl),
api.NewMockPhaseCurrents(ctrl),
}
c, err := NewCircuit(log, "foo", maxC, 0, m, 0)
c, err := New(log, "foo", maxC, 0, m, 0)
require.NoError(t, err)
return c, m
}
Expand Down
3 changes: 3 additions & 0 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/evcc-io/evcc/core/planner"
"github.com/evcc-io/evcc/core/prioritizer"
"github.com/evcc-io/evcc/core/session"
"github.com/evcc-io/evcc/core/site"
"github.com/evcc-io/evcc/core/soc"
"github.com/evcc-io/evcc/core/vehicle"
"github.com/evcc-io/evcc/push"
Expand Down Expand Up @@ -54,6 +55,8 @@ type batteryMeasurement struct {
Controllable bool `json:"controllable"`
}

var _ site.API = (*Site)(nil)

// Site is the main configuration container. A site can host multiple loadpoints.
type Site struct {
uiChan chan<- util.Param // client push messages
Expand Down
7 changes: 4 additions & 3 deletions core/site/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ type API interface {
Loadpoints() []loadpoint.API
Vehicles() Vehicles

// GetCircuit returns the assigned circuit
GetCircuit() api.Circuit

// Meta
GetTitle() string
SetTitle(string)
Expand All @@ -26,6 +23,10 @@ type API interface {
GetBatteryMeterRefs() []string
SetBatteryMeterRefs([]string)

// circuits
GetCircuit() api.Circuit
SetCircuit(api.Circuit)

//
// battery
//
Expand Down
15 changes: 10 additions & 5 deletions core/site_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,20 @@ func (site *Site) Vehicles() site.Vehicles {
return &vehicles{log: site.log}
}

// GetCircuit returns the circuit
// GetCircuit returns the root circuit
func (site *Site) GetCircuit() api.Circuit {
if site.circuit == nil {
// return untyped nil
return nil
}
site.RLock()
defer site.RUnlock()
return site.circuit
}

// SetCircuit sets the root circuit
func (site *Site) SetCircuit(circuit api.Circuit) {
site.Lock()
defer site.Unlock()
site.circuit = circuit
}

// GetPrioritySoc returns the PrioritySoc
func (site *Site) GetPrioritySoc() float64 {
site.RLock()
Expand Down
5 changes: 3 additions & 2 deletions hems/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

"github.com/evcc-io/evcc/core/site"
"github.com/evcc-io/evcc/hems/eebus"
"github.com/evcc-io/evcc/hems/semp"
"github.com/evcc-io/evcc/server"
)
Expand All @@ -19,8 +20,8 @@ func NewFromConfig(typ string, other map[string]interface{}, site site.API, http
switch strings.ToLower(typ) {
case "sma", "shm", "semp":
return semp.New(other, site, httpd)
// case "ocpp":
// return ocpp.New(other, site)
case "eebus":
return eebus.New(other, site)
default:
return nil, errors.New("unknown hems: " + typ)
}
Expand Down
Loading

0 comments on commit 6c3ecdb

Please sign in to comment.