Implement int/string/bool getters over mqtt (#30)
This commit is contained in:
parent
50595af184
commit
ca75de87c1
7 changed files with 183 additions and 51 deletions
|
|
@ -22,7 +22,7 @@ func NewConfigurableFromConfig(log *api.Logger, other map[string]interface{}) ap
|
|||
provider.NewStringGetterFromConfig(cc.Status),
|
||||
provider.NewBoolGetterFromConfig(cc.Enabled),
|
||||
provider.NewBoolSetterFromConfig("enable", cc.Enable),
|
||||
provider.NewIntSetterFromConfig("current", cc.MaxCurrent),
|
||||
provider.NewIntSetterFromConfig("maxcurrent", cc.MaxCurrent),
|
||||
)
|
||||
|
||||
return charger
|
||||
|
|
|
|||
|
|
@ -83,6 +83,20 @@ chargers:
|
|||
- name: go-e
|
||||
type: go-e # go-e charger
|
||||
uri: http://192.168.1.4 # go-e address
|
||||
- name: configurable
|
||||
type: default # Configurable charger
|
||||
status: # charger status A..F
|
||||
type: mqtt
|
||||
topic: some/topic1
|
||||
enabled: # charger enabled state (true/false or 0/1)
|
||||
type: mqtt
|
||||
topic: some/topic2
|
||||
enable: # set charger enabled state
|
||||
type: script
|
||||
cmd: /bin/sh -c "echo ${enable}"
|
||||
maxcurrent: # set charger max current
|
||||
type: script
|
||||
cmd: /bin/sh -c "echo ${maxcurrent}"
|
||||
|
||||
vehicles:
|
||||
- name: default
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -22,49 +23,9 @@ type Config struct {
|
|||
// MQTT singleton
|
||||
var MQTT *MqttClient
|
||||
|
||||
// NewStringGetterFromConfig creates a StringGetter from config
|
||||
func NewStringGetterFromConfig(pc *Config) (res StringGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.StringGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCached(res, pc.Cache).StringGetter()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewBoolGetterFromConfig creates a BoolGetter from config
|
||||
func NewBoolGetterFromConfig(pc *Config) (res BoolGetter) {
|
||||
switch pc.Type {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCached(res, pc.Cache).BoolGetter()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewFloatGetterFromConfig creates a FloatGetter from config
|
||||
func NewFloatGetterFromConfig(pc *Config) (res FloatGetter) {
|
||||
switch pc.Type {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "mqtt":
|
||||
if MQTT == nil {
|
||||
log.FATAL.Fatal("mqtt not configured")
|
||||
|
|
@ -93,9 +54,96 @@ func NewFloatGetterFromConfig(pc *Config) (res FloatGetter) {
|
|||
return
|
||||
}
|
||||
|
||||
// NewIntGetterFromConfig creates a IntGetter from config
|
||||
func NewIntGetterFromConfig(pc *Config) (res IntGetter) {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "mqtt":
|
||||
if MQTT == nil {
|
||||
log.FATAL.Fatal("mqtt not configured")
|
||||
}
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
if pc.Multiplier == 0 {
|
||||
pc.Multiplier = 1
|
||||
}
|
||||
res = MQTT.IntGetter(pc.Topic, int64(pc.Multiplier), pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.IntGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCached(res, pc.Cache).IntGetter()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewStringGetterFromConfig creates a StringGetter from config
|
||||
func NewStringGetterFromConfig(pc *Config) (res StringGetter) {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "mqtt":
|
||||
if MQTT == nil {
|
||||
log.FATAL.Fatal("mqtt not configured")
|
||||
}
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
res = MQTT.StringGetter(pc.Topic, pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.StringGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCached(res, pc.Cache).StringGetter()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewBoolGetterFromConfig creates a BoolGetter from config
|
||||
func NewBoolGetterFromConfig(pc *Config) (res BoolGetter) {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "mqtt":
|
||||
if MQTT == nil {
|
||||
log.FATAL.Fatal("mqtt not configured")
|
||||
}
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = mqttTimeout
|
||||
}
|
||||
res = MQTT.BoolGetter(pc.Topic, pc.Timeout)
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
}
|
||||
exec := NewScriptProvider(pc.Timeout)
|
||||
res = exec.BoolGetter(pc.Cmd)
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid provider type %s", pc.Type)
|
||||
}
|
||||
|
||||
if pc.Cache > 0 {
|
||||
res = NewCached(res, pc.Cache).BoolGetter()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewBoolSetterFromConfig creates a BoolSetter from config
|
||||
func NewBoolSetterFromConfig(param string, pc *Config) (res BoolSetter) {
|
||||
switch pc.Type {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
|
|
@ -110,7 +158,7 @@ func NewBoolSetterFromConfig(param string, pc *Config) (res BoolSetter) {
|
|||
|
||||
// NewIntSetterFromConfig creates a IntSetter from config
|
||||
func NewIntSetterFromConfig(param string, pc *Config) (res IntSetter) {
|
||||
switch pc.Type {
|
||||
switch strings.ToLower(pc.Type) {
|
||||
case "script":
|
||||
if pc.Timeout == 0 {
|
||||
pc.Timeout = execTimeout
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@ import (
|
|||
|
||||
var log = api.NewLogger("exec")
|
||||
|
||||
func truish(s string) bool {
|
||||
return s == "1" || strings.ToLower(s) == "true" || strings.ToLower(s) == "on"
|
||||
}
|
||||
|
||||
// Script implements shell script-based providers and setters
|
||||
type Script struct {
|
||||
timeout time.Duration
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ import (
|
|||
|
||||
var re = regexp.MustCompile(`\${(\w+)(:([a-zA-Z0-9%.]+))?}`)
|
||||
|
||||
// truish returns true if value is truish (true/1/on)
|
||||
func truish(s string) bool {
|
||||
return s == "1" || strings.ToLower(s) == "true" || strings.ToLower(s) == "on"
|
||||
}
|
||||
|
||||
// replaceFormatted replaces all occurrances of ${key} with val from the kv map.
|
||||
// All keys of kv must exist inside the string to apply replacements to
|
||||
func replaceFormatted(s string, kv map[string]interface{}) (string, error) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,28 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestTruish(t *testing.T) {
|
||||
cases := []struct {
|
||||
k string
|
||||
v bool
|
||||
}{
|
||||
{"", false},
|
||||
{"false", false},
|
||||
{"0", false},
|
||||
{"off", false},
|
||||
{"true", true},
|
||||
{"1", true},
|
||||
{"on", true},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
b := truish(c.k)
|
||||
if b != c.v {
|
||||
t.Errorf("expected %v got %v", c.v, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
cases := []struct {
|
||||
k string
|
||||
|
|
|
|||
|
|
@ -115,14 +115,37 @@ func (m *MqttClient) FloatGetter(topic string, multiplier float64, timeout time.
|
|||
}
|
||||
|
||||
// IntGetter creates handler for int64 from MQTT topic that returns cached value
|
||||
func (m *MqttClient) IntGetter(topic string, timeout time.Duration) IntGetter {
|
||||
func (m *MqttClient) IntGetter(topic string, multiplier int64, timeout time.Duration) IntGetter {
|
||||
h := &msgHandler{
|
||||
topic: topic,
|
||||
multiplier: float64(multiplier),
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
m.Listen(topic, h.Receive)
|
||||
return h.intGetter
|
||||
}
|
||||
|
||||
// StringGetter creates handler for string from MQTT topic that returns cached value
|
||||
func (m *MqttClient) StringGetter(topic string, timeout time.Duration) StringGetter {
|
||||
h := &msgHandler{
|
||||
topic: topic,
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
m.Listen(topic, h.Receive)
|
||||
return h.intGetter
|
||||
return h.stringGetter
|
||||
}
|
||||
|
||||
// BoolGetter creates handler for string from MQTT topic that returns cached value
|
||||
func (m *MqttClient) BoolGetter(topic string, timeout time.Duration) BoolGetter {
|
||||
h := &msgHandler{
|
||||
topic: topic,
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
m.Listen(topic, h.Receive)
|
||||
return h.boolGetter
|
||||
}
|
||||
|
||||
// WaitForToken synchronously waits until token operation completed
|
||||
|
|
@ -209,5 +232,29 @@ func (h *msgHandler) intGetter() (int64, error) {
|
|||
return 0, fmt.Errorf("%s invalid: '%s'", h.topic, h.payload)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
return int64(h.multiplier) * val, nil
|
||||
}
|
||||
|
||||
func (h *msgHandler) stringGetter() (string, error) {
|
||||
h.once.Do(h.waitForInitialValue)
|
||||
h.mux.Lock()
|
||||
defer h.mux.Unlock()
|
||||
|
||||
if elapsed := time.Since(h.updated); elapsed > h.timeout {
|
||||
return "", fmt.Errorf("%s outdated: %v", h.topic, elapsed.Truncate(time.Second))
|
||||
}
|
||||
|
||||
return string(h.payload), nil
|
||||
}
|
||||
|
||||
func (h *msgHandler) boolGetter() (bool, error) {
|
||||
h.once.Do(h.waitForInitialValue)
|
||||
h.mux.Lock()
|
||||
defer h.mux.Unlock()
|
||||
|
||||
if elapsed := time.Since(h.updated); elapsed > h.timeout {
|
||||
return false, fmt.Errorf("%s outdated: %v", h.topic, elapsed.Truncate(time.Second))
|
||||
}
|
||||
|
||||
return truish(string(h.payload)), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue