Skip to content

Commit 7eb85ad

Browse files
authored
Support SMA Sunny Home Manager as Energy Management System (#353)
1 parent 1387ec1 commit 7eb85ad

File tree

14 files changed

+751
-13
lines changed

14 files changed

+751
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ linux-*.Dockerfile
88
!evcc.dist.yaml
99
!modules/**
1010
dist
11+
*.py

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ EVCC is an extensible EV Charge Controller with PV integration implemented in [G
3434
- [Charger](#charger)
3535
- [Meter](#meter)
3636
- [Vehicle](#vehicle)
37+
- [Home Energy Management System](#home-energy-management-system)
3738
- [Plugins](#plugins)
3839
- [Modbus](#modbus-read-only)
3940
- [MQTT](#mqtt-readwrite)
@@ -216,6 +217,16 @@ Available vehicle implementations are:
216217

217218
Configuration examples are documented at [andig/evcc-config#vehicles](https://github.com/andig/evcc-config#vehicles)
218219

220+
### Home Energy Management System
221+
222+
EVCC can integrate itself with Home Energy Management Systems. At this time, the SMA Home Manager (SHM) is the only supported system. To enable add
223+
224+
```yaml
225+
hems: sma
226+
```
227+
228+
to the configuration. The EVCC loadpoints can then be added to the SHM configuration.
229+
219230
## Plugins
220231

221232
Plugins are used to integrate various devices and external data sources with EVCC. Plugins can be used in combination with a `default` type meter, charger or vehicle.

cmd/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type config struct {
1919
Interval time.Duration
2020
Mqtt provider.MqttConfig
2121
Influx server.InfluxConfig
22+
HEMS string
2223
Menu []server.MenuConfig
2324
Messaging messagingConfig
2425
Meters []qualifiedConfig

cmd/root.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ func run(cmd *cobra.Command, args []string) {
156156
socketHub := server.NewSocketHub()
157157
httpd := server.NewHTTPd(uri, conf.Menu, site, socketHub, cache)
158158

159+
// start HEMS server
160+
if conf.HEMS != "" {
161+
hems := configureHEMS(conf.HEMS, site, cache, httpd)
162+
go hems.Run()
163+
}
164+
159165
// publish to UI
160166
go socketHub.Run(tee.Attach(), cache)
161167

cmd/setup.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/andig/evcc/core"
10+
"github.com/andig/evcc/hems"
1011
"github.com/andig/evcc/provider"
1112
"github.com/andig/evcc/push"
1213
"github.com/andig/evcc/server"
@@ -51,6 +52,16 @@ func configureMQTT(conf provider.MqttConfig) {
5152
provider.MQTT = provider.NewMqttClient(conf.Broker, conf.User, conf.Password, mqttClientID(), 1)
5253
}
5354

55+
// setup HEMS
56+
func configureHEMS(conf string, site *core.Site, cache *util.Cache, httpd *server.HTTPd) hems.HEMS {
57+
hems, err := hems.NewFromConfig(conf, site, cache, httpd)
58+
if err != nil {
59+
log.FATAL.Fatal(err)
60+
}
61+
return hems
62+
}
63+
64+
// setup messaging
5465
func configureMessengers(conf messagingConfig, cache *util.Cache) chan push.Event {
5566
notificationChan := make(chan push.Event, 1)
5667
notificationHub := push.NewHub(conf.Events, cache)

core/loadpoint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ func (lp *LoadPoint) publishSoC() {
603603
}
604604

605605
lp.publish("socCharge", -1)
606-
lp.publish("chargeEstimate", -1)
606+
lp.publish("chargeEstimate", time.Duration(-1))
607607
}
608608

609609
// Update is the main control function. It reevaluates meters and charger state

core/site.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ func (site *Site) SetTargetSoC(targetSoC int) {
146146
}
147147
}
148148

149-
func (lp *LoadPoint) hasChargeMeter() bool {
149+
// HasChargeMeter determines if a physical charge meter is attached
150+
func (lp *LoadPoint) HasChargeMeter() bool {
150151
_, isWrapped := lp.chargeMeter.(*wrapper.ChargeMeter)
151152
return lp.chargeMeter != nil && !isWrapped
152153
}
@@ -172,7 +173,7 @@ func (site *Site) Configuration() SiteConfiguration {
172173
Phases: lp.Phases,
173174
MinCurrent: lp.MinCurrent,
174175
MaxCurrent: lp.MaxCurrent,
175-
ChargeMeter: lp.hasChargeMeter(),
176+
ChargeMeter: lp.HasChargeMeter(),
176177
}
177178

178179
if lp.vehicle != nil {
@@ -215,8 +216,8 @@ func (site *Site) DumpConfig() {
215216
lp.log.INFO.Printf("loadpoint %d config:", i+1)
216217

217218
lp.log.INFO.Printf(" vehicle %s", presence[lp.vehicle != nil])
218-
lp.log.INFO.Printf(" charge %s", presence[lp.hasChargeMeter()])
219-
if lp.hasChargeMeter() {
219+
lp.log.INFO.Printf(" charge %s", presence[lp.HasChargeMeter()])
220+
if lp.HasChargeMeter() {
220221
lp.log.INFO.Println(" charge meter config:")
221222
logMeter(site.log, lp.chargeMeter)
222223
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ require (
2727
github.com/joeshaw/carwings v0.0.0-20191118152321-61b46581307a
2828
github.com/jsgoecke/tesla v0.0.0-20200530171421-e02ebd220e5a
2929
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
30+
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d
31+
github.com/kr/pretty v0.2.0 // indirect
3032
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
3133
github.com/mitchellh/mapstructure v1.3.2
3234
github.com/mjibson/esc v0.2.0
@@ -41,6 +43,7 @@ require (
4143
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e
4244
github.com/volkszaehler/mbmd v0.0.0-20200831092453-b235d6a65b21
4345
golang.org/x/net v0.0.0-20200707034311-ab3426394381
46+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
4447
gopkg.in/ini.v1 v1.57.0
4548
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
4649
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,14 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3
225225
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
226226
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
227227
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
228+
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
229+
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
228230
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
229231
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
230232
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
231233
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
234+
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
235+
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
232236
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
233237
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
234238
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -569,6 +573,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
569573
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
570574
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
571575
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
576+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
577+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
572578
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
573579
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
574580
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

hems/config.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package hems
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/andig/evcc/core"
8+
"github.com/andig/evcc/hems/semp"
9+
"github.com/andig/evcc/server"
10+
"github.com/andig/evcc/util"
11+
)
12+
13+
// HEMS describes the HEMS system interface
14+
type HEMS interface {
15+
Run()
16+
}
17+
18+
// NewFromConfig creates new HEMS from config
19+
func NewFromConfig(typ string, site *core.Site, cache *util.Cache, httpd *server.HTTPd) (HEMS, error) {
20+
switch strings.ToLower(typ) {
21+
case "sma", "shm", "semp":
22+
return semp.New(site, cache, httpd)
23+
default:
24+
return nil, errors.New("unknown hems: " + typ)
25+
}
26+
}

0 commit comments

Comments
 (0)