103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/andig/evcc/api"
|
|
"github.com/andig/evcc/core"
|
|
"github.com/andig/evcc/provider"
|
|
"github.com/andig/evcc/util"
|
|
)
|
|
|
|
// MQTT is the MQTT server. It uses the MQTT client for publishing.
|
|
type MQTT struct {
|
|
Handler *provider.MqttClient
|
|
root string
|
|
}
|
|
|
|
// NewMQTT creates MQTT server
|
|
func NewMQTT(root string) *MQTT {
|
|
return &MQTT{
|
|
Handler: provider.MQTT,
|
|
root: root,
|
|
}
|
|
}
|
|
|
|
func (m *MQTT) encode(v interface{}) string {
|
|
var s string
|
|
switch val := v.(type) {
|
|
case time.Time:
|
|
s = strconv.FormatInt(val.Unix(), 10)
|
|
case time.Duration:
|
|
// must be before stringer to convert to seconds instead of string
|
|
s = fmt.Sprintf("%d", int64(val.Seconds()))
|
|
case fmt.Stringer, string:
|
|
s = fmt.Sprintf("%s", val)
|
|
case float64:
|
|
s = fmt.Sprintf("%.3f", val)
|
|
default:
|
|
s = fmt.Sprintf("%v", val)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (m *MQTT) publish(topic string, retained bool, payload interface{}) {
|
|
token := m.Handler.Client.Publish(topic, m.Handler.Qos, retained, m.encode(payload))
|
|
go m.Handler.WaitForToken(token)
|
|
}
|
|
|
|
type apiHandler interface {
|
|
SetMode(api.ChargeMode)
|
|
SetTargetSoC(int)
|
|
}
|
|
|
|
func (m *MQTT) listenSetters(topic string, apiHandler apiHandler) {
|
|
m.Handler.Listen(topic+"/mode/set", func(payload string) {
|
|
apiHandler.SetMode(api.ChargeMode(payload))
|
|
})
|
|
m.Handler.Listen(topic+"/targetsoc/set", func(payload string) {
|
|
soc, err := strconv.Atoi(payload)
|
|
if err == nil {
|
|
apiHandler.SetTargetSoC(soc)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Run starts the MQTT publisher for the MQTT API
|
|
func (m *MQTT) Run(site *core.Site, in <-chan util.Param) {
|
|
topic := fmt.Sprintf("%s/site", m.root)
|
|
m.listenSetters(topic, site)
|
|
|
|
// number of loadpoints
|
|
topic = fmt.Sprintf("%s/loadpoints", m.root)
|
|
m.publish(topic, true, len(site.LoadPoints()))
|
|
|
|
for id, lp := range site.LoadPoints() {
|
|
topic := fmt.Sprintf("%s/loadpoints/%d", m.root, id)
|
|
m.listenSetters(topic, lp)
|
|
}
|
|
|
|
// alive indicator
|
|
updated := time.Now().Unix()
|
|
m.publish(fmt.Sprintf("%s/updated", m.root), true, updated)
|
|
|
|
for p := range in {
|
|
topic := fmt.Sprintf("%s/site", m.root)
|
|
if p.LoadPoint != nil {
|
|
topic = fmt.Sprintf("%s/loadpoints/%d", m.root, *p.LoadPoint)
|
|
}
|
|
|
|
// alive indicator
|
|
if now := time.Now().Unix(); now != updated {
|
|
updated = now
|
|
m.publish(fmt.Sprintf("%s/updated", m.root), true, updated)
|
|
}
|
|
|
|
// value
|
|
topic += "/" + strings.ToLower(p.Key)
|
|
m.publish(topic, false, p.Val)
|
|
}
|
|
}
|