Skip to content

Commit

Permalink
Added support for SMA device config by serial (#121)
Browse files Browse the repository at this point in the history
* Added support for SMA device config by serial

- The SMA Home Manager or Energy Meter device can now be either defined via its IP or its serial number
- Only URI or serial number needs to be defined in the config file

* Add fatal error when serial and uri are missing
  • Loading branch information
Andreas Linde committed May 11, 2020
1 parent 08cee90 commit 0c18e47
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 11 deletions.
3 changes: 2 additions & 1 deletion evcc.dist.yaml
Expand Up @@ -69,7 +69,8 @@ meters:
timeout: 3s # kill script after 3 seconds
- name: sma
type: sma # SMA Home Manager 2.0 or SMA Energy Meter 30
uri: 192.168.1.4 # IP address of the device
serial: 1234567890 # Serial number of the device, if this is defined uri is not needed!
uri: 192.168.1.4 # IP address of the device, if this is defined serial is not needed!
- name: sdm
type: modbus
model: sdm
Expand Down
19 changes: 14 additions & 5 deletions meter/sma.go
Expand Up @@ -19,6 +19,7 @@ const (
type SMA struct {
log *util.Logger
uri string
serial string
power float64
energy float64
powerO sma.Obis
Expand All @@ -32,30 +33,38 @@ type SMA struct {
// NewSMAFromConfig creates a SMA Meter from generic config
func NewSMAFromConfig(log *util.Logger, other map[string]interface{}) api.Meter {
cc := struct {
URI, Power, Energy string
URI, Serial, Power, Energy string
}{}
util.DecodeOther(log, other, &cc)

return NewSMA(cc.URI, cc.Power, cc.Energy)
return NewSMA(cc.URI, cc.Serial, cc.Power, cc.Energy)
}

// NewSMA creates a SMA Meter
func NewSMA(uri, power, energy string) api.Meter {
func NewSMA(uri, serial, power, energy string) api.Meter {
log := util.NewLogger("sma ")

sm := &SMA{
log: log,
uri: uri,
serial: serial,
powerO: sma.Obis(power),
energyO: sma.Obis(energy),
recv: make(chan sma.Telegram),
}

if sma.Instance == nil {
sma.Instance = sma.New(log, sm.uri)
sma.Instance = sma.New(log)
}

sma.Instance.Subscribe(uri, sm.recv)
// we only need to subscribe to one of the two possible identifiers
if uri != "" {
sma.Instance.Subscribe(uri, sm.recv)
} else if serial != "" {
sma.Instance.Subscribe(serial, sm.recv)
} else {
log.FATAL.Fatalf("config: missing uri or serial")
}

go sm.receive()

Expand Down
10 changes: 5 additions & 5 deletions meter/sma/listener.go
Expand Up @@ -93,7 +93,7 @@ type Listener struct {
}

// New creates a Listener
func New(log *util.Logger, addr string) *Listener {
func New(log *util.Logger) *Listener {
// Parse the string address
gaddr, err := net.ResolveUDPAddr("udp4", multicastAddr)
if err != nil {
Expand Down Expand Up @@ -178,23 +178,23 @@ func (l *Listener) listen() {
}

// Subscribe adds a client address and message channel
func (l *Listener) Subscribe(addr string, c chan<- Telegram) {
func (l *Listener) Subscribe(identifier string, c chan<- Telegram) {
l.mux.Lock()
defer l.mux.Unlock()

if l.clients == nil {
l.clients = make(map[string]chan<- Telegram)
}

l.clients[addr] = c
l.clients[identifier] = c
}

func (l *Listener) send(msg Telegram) {
l.mux.Lock()
defer l.mux.Unlock()

for addr, client := range l.clients {
if addr == msg.Addr {
for identifier, client := range l.clients {
if identifier == msg.Addr || identifier == msg.Serial {
select {
case client <- msg:
default:
Expand Down

0 comments on commit 0c18e47

Please sign in to comment.