-
-
Notifications
You must be signed in to change notification settings - Fork 706
/
lgess.go
145 lines (121 loc) Β· 3.44 KB
/
lgess.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package meter
import (
"errors"
"fmt"
"strings"
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/meter/lgpcs"
"github.com/evcc-io/evcc/util"
)
/*
This meter supports the LGESS HOME 8 and LGESS HOME 10 systems from LG with / without battery.
** Usages **
The following usages are supported:
- grid ... for reading the power imported or exported to the grid
- pv ... for reading the power produced by the pv
- battery ... for reading the power imported or exported to the battery
** Example configuration **
meters:
- name: GridMeter
type: lgess
usage: grid
uri: https://192.168.1.23
password: "DE200....."
- name: PvMeter
type: lgess
usage: pv
- name: BatteryMeter
type: lgess
usage: battery
** Limitations **
It is not allowed to provide different URIs or passwords for different lgess meters since always the
same hardware instance is accessed with the different usages.
*/
// LgEss implements the api.Meter interface
type LgEss struct {
usage string // grid, pv, battery
lp *lgpcs.Com // communication with the lgpcs device
}
func init() {
registry.Add("lgess", NewLgEssFromConfig)
}
//go:generate go run ../cmd/tools/decorate.go -f decorateLgEss -b *LgEss -r api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatteryCapacity,Capacity,func() float64"
// NewLgEssFromConfig creates an LgEss Meter from generic config
func NewLgEssFromConfig(other map[string]interface{}) (api.Meter, error) {
cc := struct {
capacity `mapstructure:",squash"`
URI, Usage string
Registration, Password string
Cache time.Duration
}{
Cache: time.Second,
}
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
if cc.Usage == "" {
return nil, errors.New("missing usage")
}
return NewLgEss(cc.URI, cc.Usage, cc.Registration, cc.Password, cc.Cache, cc.capacity.Decorator())
}
// NewLgEss creates an LgEss Meter
func NewLgEss(uri, usage, registration, password string, cache time.Duration, capacity func() float64) (api.Meter, error) {
lp, err := lgpcs.GetInstance(uri, registration, password, cache)
if err != nil {
return nil, err
}
m := &LgEss{
usage: strings.ToLower(usage),
lp: lp,
}
// decorate api.MeterEnergy
var totalEnergy func() (float64, error)
if m.usage == "grid" {
totalEnergy = m.totalEnergy
}
// decorate api.BatterySoc
var batterySoc func() (float64, error)
if usage == "battery" {
batterySoc = m.batterySoc
}
return decorateLgEss(m, totalEnergy, batterySoc, capacity), nil
}
// CurrentPower implements the api.Meter interface
func (m *LgEss) CurrentPower() (float64, error) {
data, err := m.lp.Data()
if err != nil {
return 0, err
}
switch m.usage {
case "grid":
return data.GridPower, nil
case "pv":
return data.PvTotalPower, nil
case "battery":
return data.BatConvPower, nil
default:
return 0, fmt.Errorf("invalid usage: %s", m.usage)
}
}
// totalEnergy implements the api.MeterEnergy interface
func (m *LgEss) totalEnergy() (float64, error) {
data, err := m.lp.Data()
if err != nil {
return 0, err
}
switch m.usage {
case "grid":
return data.CurrentGridFeedInEnergy / 1e3, nil
default:
return 0, fmt.Errorf("invalid usage: %s", m.usage)
}
}
// batterySoc implements the api.Battery interface
func (m *LgEss) batterySoc() (float64, error) {
data, err := m.lp.Data()
if err != nil {
return 0, err
}
return data.BatUserSoc, nil
}