Split common utility functions into util package (#64)

This commit is contained in:
andig 2020-04-27 18:49:04 +02:00
parent 56ad3dad95
commit 1729399ef9
44 changed files with 177 additions and 193 deletions

View file

@ -3,6 +3,7 @@ package charger
import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
)
// Charger is an api.Charger implementation with configurable getters and setters.
@ -14,9 +15,9 @@ type Charger struct {
}
// NewConfigurableFromConfig creates a new configurable charger
func NewConfigurableFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewConfigurableFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ Status, Enable, Enabled, MaxCurrent provider.Config }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
charger := NewConfigurable(
provider.NewStringGetterFromConfig(log, cc.Status),

View file

@ -4,12 +4,13 @@ import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
type apiFunction string
// NewFromConfig creates charger from configuration
func NewFromConfig(log *api.Logger, typ string, other map[string]interface{}) api.Charger {
func NewFromConfig(log *util.Logger, typ string, other map[string]interface{}) api.Charger {
var c api.Charger
switch strings.ToLower(typ) {

View file

@ -6,6 +6,7 @@ import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -43,14 +44,14 @@ type EVSEListEntry struct {
// EVSEWifi charger implementation
type EVSEWifi struct {
*api.HTTPHelper
*util.HTTPHelper
uri string
}
// NewEVSEWifiFromConfig creates a EVSEWifi charger from generic config
func NewEVSEWifiFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewEVSEWifiFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ URI string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewEVSEWifi(cc.URI)
}
@ -58,7 +59,7 @@ func NewEVSEWifiFromConfig(log *api.Logger, other map[string]interface{}) api.Ch
// NewEVSEWifi creates EVSEWifi charger
func NewEVSEWifi(uri string) api.Charger {
evse := &EVSEWifi{
HTTPHelper: api.NewHTTPHelper(api.NewLogger("wifi")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("wifi")),
uri: strings.TrimRight(uri, "/") + "/",
}

View file

@ -5,6 +5,7 @@ import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -26,14 +27,14 @@ type goeStatusResponse struct {
// GoE charger implementation
type GoE struct {
*api.HTTPHelper
*util.HTTPHelper
uri string
}
// NewGoEFromConfig creates a go-e charger from generic config
func NewGoEFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewGoEFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ URI string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewGoE(cc.URI)
}
@ -41,7 +42,7 @@ func NewGoEFromConfig(log *api.Logger, other map[string]interface{}) api.Charger
// NewGoE creates GoE charger
func NewGoE(URI string) *GoE {
c := &GoE{
HTTPHelper: api.NewHTTPHelper(api.NewLogger("go-e")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("go-e")),
uri: strings.TrimRight(URI, "/"),
}

View file

@ -11,6 +11,7 @@ import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -56,7 +57,7 @@ type MCCCurrentCableInformation struct {
// MobileConnect charger supporting devices from Audi, Bentley, Porsche
type MobileConnect struct {
*api.HTTPHelper
*util.HTTPHelper
uri string
password string
token string
@ -66,9 +67,9 @@ type MobileConnect struct {
}
// NewMobileConnectFromConfig creates a MCC charger from generic config
func NewMobileConnectFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewMobileConnectFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ URI, Password string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewMobileConnect(cc.URI, cc.Password)
}
@ -76,7 +77,7 @@ func NewMobileConnectFromConfig(log *api.Logger, other map[string]interface{}) a
// NewMobileConnect creates MCC charger
func NewMobileConnect(uri string, password string) *MobileConnect {
mcc := &MobileConnect{
HTTPHelper: api.NewHTTPHelper(api.NewLogger("mcc ")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("mcc ")),
uri: strings.TrimRight(uri, "/"),
password: password,
}

View file

@ -10,6 +10,7 @@ import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
// HTTP testing appproach from http://hassansin.github.io/Unit-Testing-http-client-in-Go
@ -36,7 +37,7 @@ func NewTestClient(fn roundTripFunc) *http.Client {
// NewTestMobileConnect .
func NewTestMobileConnect(t *testing.T, responses []apiResponse) *MobileConnect {
mcc := &MobileConnect{
HTTPHelper: api.NewHTTPHelper(nil),
HTTPHelper: util.NewHTTPHelper(nil),
uri: "http://192.168.1.1",
password: "none",
token: "token",

View file

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -58,16 +59,16 @@ type NRGDeviceMetadata struct {
// NRGKick charger implementation
type NRGKick struct {
*api.HTTPHelper
*util.HTTPHelper
IP string
MacAddress string
Password string
}
// NewNRGKickFromConfig creates a NRGKick charger from generic config
func NewNRGKickFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewNRGKickFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ IP, MacAddress, Password string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewNRGKick(cc.IP, cc.MacAddress, cc.Password)
}
@ -75,7 +76,7 @@ func NewNRGKickFromConfig(log *api.Logger, other map[string]interface{}) api.Cha
// NewNRGKick creates NRGKick charger
func NewNRGKick(IP, MacAddress, Password string) *NRGKick {
nrg := &NRGKick{
HTTPHelper: api.NewHTTPHelper(api.NewLogger("kick")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("kick")),
IP: IP,
MacAddress: MacAddress,
Password: Password,

View file

@ -5,6 +5,7 @@ import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/grid-x/modbus"
)
@ -18,22 +19,22 @@ const (
// Phoenix is an api.ChargeController implementation for Phoenix EM-CP-PP-ETH wallboxes.
// It uses Modbus TCP to communicate with the wallbox at modbus client id 255.
type Phoenix struct {
log *api.Logger
log *util.Logger
client modbus.Client
handler *modbus.TCPClientHandler
}
// NewPhoenixFromConfig creates a Phoenix charger from generic config
func NewPhoenixFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewPhoenixFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ URI string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewPhoenix(cc.URI)
}
// NewPhoenix creates a Phoenix charger
func NewPhoenix(conn string) api.Charger {
log := api.NewLogger("phoe")
log := util.NewLogger("phoe")
if conn == "" {
log.FATAL.Fatal("missing connection")
}

View file

@ -5,12 +5,13 @@ import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/grid-x/modbus"
)
// SimpleEVSE charger implementation
type SimpleEVSE struct {
log *api.Logger
log *util.Logger
client modbus.Client
handler modbus.ClientHandler
}
@ -22,16 +23,16 @@ const (
)
// NewSimpleEVSEFromConfig creates a SimpleEVSE charger from generic config
func NewSimpleEVSEFromConfig(log *api.Logger, other map[string]interface{}) api.Charger {
func NewSimpleEVSEFromConfig(log *util.Logger, other map[string]interface{}) api.Charger {
cc := struct{ URI, Device string }{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewSimpleEVSE(cc.URI, cc.Device)
}
// NewSimpleEVSE creates SimpleEVSE charger
func NewSimpleEVSE(conn, device string) api.Charger {
log := api.NewLogger("evse")
log := util.NewLogger("evse")
var handler modbus.ClientHandler
if conn != "" && device != "" {

View file

@ -6,6 +6,7 @@ import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/grid-x/modbus"
)
@ -27,19 +28,19 @@ const (
// Phoenix EV-CC-AC1-M3-CBC-RCM-ETH controller.
// It uses Modbus TCP to communicate with the wallbox at modbus client id 255.
type Wallbe struct {
log *api.Logger
log *util.Logger
client modbus.Client
handler *modbus.TCPClientHandler
factor int64
}
// NewWallbeFromConfig creates a Wallbe charger from generic config
func NewWallbeFromConfig(log *api.Logger, other map[string]interface{}) *Wallbe {
func NewWallbeFromConfig(log *util.Logger, other map[string]interface{}) *Wallbe {
cc := struct {
URI string
Legacy bool
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
wb := NewWallbe(cc.URI)
@ -64,7 +65,7 @@ func NewWallbe(conn string) *Wallbe {
handler.ProtocolRecoveryTimeout = protocolTimeout
wb := &Wallbe{
log: api.NewLogger("wlbe"),
log: util.NewLogger("wlbe"),
client: client,
handler: handler,
factor: 10,

View file

@ -6,6 +6,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/andig/evcc/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -22,7 +23,7 @@ func init() {
}
func runCharger(cmd *cobra.Command, args []string) {
configureLogging()
util.LogLevel(viper.GetString("log"))
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config

View file

@ -6,6 +6,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/andig/evcc/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -22,7 +23,7 @@ func init() {
}
func runMeter(cmd *cobra.Command, args []string) {
configureLogging()
util.LogLevel(viper.GetString("log"))
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config

View file

@ -5,10 +5,10 @@ import (
"os"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/core"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/andig/evcc/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -16,7 +16,7 @@ import (
)
var (
log = api.NewLogger("main")
log = util.NewLogger("main")
cfgFile string
)
@ -114,17 +114,6 @@ func Execute() {
}
}
func configureLogging() {
level := viper.GetString("log")
api.OutThreshold = api.LogLevelToThreshold(level)
api.LogThreshold = api.OutThreshold
api.Loggers(func(name string, logger *api.Logger) {
logger.SetStdoutThreshold(api.OutThreshold)
})
}
// checkVersion validates if updates are available
func checkVersion() {
githubTag := &latest.GithubTag{
@ -161,12 +150,12 @@ func tee(in chan core.Param) (chan core.Param, <-chan core.Param) {
}
func run(cmd *cobra.Command, args []string) {
configureLogging()
util.LogLevel(viper.GetString("log"))
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config and re-configure logging after reading config file
conf := loadConfigFile(cfgFile)
configureLogging()
util.LogLevel(viper.GetString("log"))
go checkVersion()

View file

@ -5,9 +5,9 @@ import (
"math/rand"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/core"
"github.com/andig/evcc/push"
"github.com/andig/evcc/util"
"github.com/spf13/viper"
)
@ -46,7 +46,7 @@ func loadConfig(conf config, eventsChan chan push.Event) (loadPoints []*core.Loa
// decode slice into slice of maps
var lpm []map[string]interface{}
api.DecodeOther(log, lps, &lpm)
util.DecodeOther(log, lps, &lpm)
for _, lpc := range lpm {
lp := core.NewLoadPointFromConfig(log, cp, lpc)

View file

@ -6,6 +6,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/andig/evcc/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -22,7 +23,7 @@ func init() {
}
func runVehicle(cmd *cobra.Command, args []string) {
configureLogging()
util.LogLevel(viper.GetString("log"))
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config

View file

@ -9,6 +9,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/core/wrapper"
"github.com/andig/evcc/push"
"github.com/andig/evcc/util"
"github.com/pkg/errors"
evbus "github.com/asaskevich/EventBus"
@ -98,9 +99,9 @@ type configProvider interface {
}
// NewLoadPointFromConfig creates a new loadpoint
func NewLoadPointFromConfig(log *api.Logger, cp configProvider, other map[string]interface{}) *LoadPoint {
func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[string]interface{}) *LoadPoint {
lp := NewLoadPoint()
api.DecodeOther(log, other, &lp)
util.DecodeOther(log, other, &lp)
if lp.ChargerRef != "" {
lp.charger = cp.Charger(lp.ChargerRef)

View file

@ -1,5 +1,5 @@
package core
import "github.com/andig/evcc/api"
import "github.com/andig/evcc/util"
var log = api.NewLogger("load")
var log = util.NewLogger("load")

View file

@ -1,5 +1,5 @@
package wrapper
import "github.com/andig/evcc/api"
import "github.com/andig/evcc/util"
var log = api.NewLogger("wrap")
var log = util.NewLogger("wrap")

View file

@ -4,10 +4,11 @@ import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
// NewFromConfig creates meter from configuration
func NewFromConfig(log *api.Logger, typ string, other map[string]interface{}) api.Meter {
func NewFromConfig(log *util.Logger, typ string, other map[string]interface{}) api.Meter {
var c api.Meter
switch strings.ToLower(typ) {

View file

@ -3,6 +3,7 @@ package meter
import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
)
// CompositeMeter decorates a Meter with MeterEnergy.
@ -12,12 +13,12 @@ type CompositeMeter struct {
}
// NewConfigurableFromConfig creates api.Meter from config
func NewConfigurableFromConfig(log *api.Logger, other map[string]interface{}) api.Meter {
func NewConfigurableFromConfig(log *util.Logger, other map[string]interface{}) api.Meter {
cc := struct {
Power provider.Config
Energy *provider.Config // optional
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
m := NewConfigurable(provider.NewFloatGetterFromConfig(log, cc.Power))

View file

@ -7,6 +7,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/meter/sma"
"github.com/andig/evcc/util"
)
const (
@ -16,7 +17,7 @@ const (
// SMA supporting SMA Home Manager 2.0 and SMA Energy Meter 30
type SMA struct {
log *api.Logger
log *util.Logger
uri string
power float64
updated time.Time
@ -26,18 +27,18 @@ type SMA struct {
}
// NewSMAFromConfig creates a SMA Meter from generic config
func NewSMAFromConfig(log *api.Logger, other map[string]interface{}) api.Meter {
func NewSMAFromConfig(log *util.Logger, other map[string]interface{}) api.Meter {
sm := struct {
URI string
}{}
api.DecodeOther(log, other, &sm)
util.DecodeOther(log, other, &sm)
return NewSMA(sm.URI)
}
// NewSMA creates a SMA Meter
func NewSMA(uri string) *SMA {
log := api.NewLogger("sma ")
log := util.NewLogger("sma ")
sm := &SMA{
log: log,

View file

@ -8,7 +8,7 @@ import (
"strconv"
"sync"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -85,13 +85,13 @@ type Telegram struct {
// Listener for receiving SMA multicast data packages
type Listener struct {
mux sync.Mutex
log *api.Logger
log *util.Logger
conn *net.UDPConn
clients map[string]chan<- Telegram
}
// New creates a Listener
func New(log *api.Logger, addr string) *Listener {
func New(log *util.Logger, addr string) *Listener {
// Parse the string address
gaddr, err := net.ResolveUDPAddr("udp4", multicastAddr)
if err != nil {

View file

@ -3,13 +3,13 @@ package provider
import (
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/benbjohnson/clock"
)
// Cached wraps a getter with a cache
type Cached struct {
log *api.Logger
log *util.Logger
clock clock.Clock
updated time.Time
cache time.Duration
@ -18,7 +18,7 @@ type Cached struct {
}
// NewCached wraps a getter with a cache
func NewCached(log *api.Logger, getter interface{}, cache time.Duration) *Cached {
func NewCached(log *util.Logger, getter interface{}, cache time.Duration) *Cached {
return &Cached{
log: log,
clock: clock.New(),

View file

@ -4,7 +4,7 @@ import (
"strings"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
const (
@ -34,13 +34,13 @@ type scriptConfig struct {
// MQTT singleton
var MQTT *MqttClient
func mqttFromConfig(log *api.Logger, other map[string]interface{}) mqttConfig {
func mqttFromConfig(log *util.Logger, other map[string]interface{}) mqttConfig {
if MQTT == nil {
log.FATAL.Fatal("mqtt not configured")
}
var pc mqttConfig
api.DecodeOther(log, other, &pc)
util.DecodeOther(log, other, &pc)
if pc.Multiplier == 0 {
pc.Multiplier = 1
@ -49,9 +49,9 @@ func mqttFromConfig(log *api.Logger, other map[string]interface{}) mqttConfig {
return pc
}
func scriptFromConfig(log *api.Logger, other map[string]interface{}) scriptConfig {
func scriptFromConfig(log *util.Logger, other map[string]interface{}) scriptConfig {
var pc scriptConfig
api.DecodeOther(log, other, &pc)
util.DecodeOther(log, other, &pc)
if pc.Timeout == 0 {
pc.Timeout = execTimeout
@ -61,7 +61,7 @@ func scriptFromConfig(log *api.Logger, other map[string]interface{}) scriptConfi
}
// NewFloatGetterFromConfig creates a FloatGetter from config
func NewFloatGetterFromConfig(log *api.Logger, config Config) (res FloatGetter) {
func NewFloatGetterFromConfig(log *util.Logger, config Config) (res FloatGetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)
@ -82,7 +82,7 @@ func NewFloatGetterFromConfig(log *api.Logger, config Config) (res FloatGetter)
}
// NewIntGetterFromConfig creates a IntGetter from config
func NewIntGetterFromConfig(log *api.Logger, config Config) (res IntGetter) {
func NewIntGetterFromConfig(log *util.Logger, config Config) (res IntGetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)
@ -103,7 +103,7 @@ func NewIntGetterFromConfig(log *api.Logger, config Config) (res IntGetter) {
}
// NewStringGetterFromConfig creates a StringGetter from config
func NewStringGetterFromConfig(log *api.Logger, config Config) (res StringGetter) {
func NewStringGetterFromConfig(log *util.Logger, config Config) (res StringGetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)
@ -124,7 +124,7 @@ func NewStringGetterFromConfig(log *api.Logger, config Config) (res StringGetter
}
// NewBoolGetterFromConfig creates a BoolGetter from config
func NewBoolGetterFromConfig(log *api.Logger, config Config) (res BoolGetter) {
func NewBoolGetterFromConfig(log *util.Logger, config Config) (res BoolGetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)
@ -143,7 +143,7 @@ func NewBoolGetterFromConfig(log *api.Logger, config Config) (res BoolGetter) {
}
// NewIntSetterFromConfig creates a IntSetter from config
func NewIntSetterFromConfig(log *api.Logger, param string, config Config) (res IntSetter) {
func NewIntSetterFromConfig(log *util.Logger, param string, config Config) (res IntSetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)
@ -159,7 +159,7 @@ func NewIntSetterFromConfig(log *api.Logger, param string, config Config) (res I
}
// NewBoolSetterFromConfig creates a BoolSetter from config
func NewBoolSetterFromConfig(log *api.Logger, param string, config Config) (res BoolSetter) {
func NewBoolSetterFromConfig(log *util.Logger, param string, config Config) (res BoolSetter) {
switch strings.ToLower(config.Type) {
case "mqtt":
pc := mqttFromConfig(log, config.Other)

View file

@ -8,13 +8,13 @@ import (
"strings"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/kballard/go-shellquote"
)
// Script implements shell script-based providers and setters
type Script struct {
log *api.Logger
log *util.Logger
timeout time.Duration
}
@ -22,7 +22,7 @@ type Script struct {
// Script execution is aborted after given timeout.
func NewScriptProvider(timeout time.Duration) *Script {
return &Script{
log: api.NewLogger("exec"),
log: util.NewLogger("exec"),
timeout: timeout,
}
}
@ -103,7 +103,7 @@ func (e *Script) BoolGetter(script string) BoolGetter {
return false, err
}
return truish(s), nil
return util.Truish(s), nil
}
}
@ -111,7 +111,7 @@ func (e *Script) BoolGetter(script string) BoolGetter {
func (e *Script) IntSetter(param, script string) IntSetter {
// return func to access cached value
return func(i int64) error {
cmd, err := replaceFormatted(script, map[string]interface{}{
cmd, err := util.ReplaceFormatted(script, map[string]interface{}{
param: i,
})
if err != nil {
@ -131,7 +131,7 @@ func (e *Script) IntSetter(param, script string) IntSetter {
func (e *Script) BoolSetter(param, script string) BoolSetter {
// return func to access cached value
return func(b bool) error {
cmd, err := replaceFormatted(script, map[string]interface{}{
cmd, err := util.ReplaceFormatted(script, map[string]interface{}{
param: b,
})
if err != nil {

View file

@ -4,7 +4,7 @@ import (
"math"
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/volkszaehler/mbmd/meters"
"github.com/volkszaehler/mbmd/meters/rs485"
"github.com/volkszaehler/mbmd/meters/sunspec"
@ -12,7 +12,7 @@ import (
// Modbus implements modbus RTU and TCP access
type Modbus struct {
log *api.Logger
log *util.Logger
conn meters.Connection
device meters.Device
slaveID uint8
@ -35,14 +35,14 @@ func modbusConnection(key string, newConn meters.Connection) meters.Connection {
}
// NewModbusFromConfig creates Modbus plugin
func NewModbusFromConfig(log *api.Logger, typ string, other map[string]interface{}) *Modbus {
func NewModbusFromConfig(log *util.Logger, typ string, other map[string]interface{}) *Modbus {
cc := struct {
URI, Device, Comset string
Meter, Value string
Baudrate int
ID uint8
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
var conn meters.Connection
var device meters.Device
@ -62,7 +62,7 @@ func NewModbusFromConfig(log *api.Logger, typ string, other map[string]interface
log.FATAL.Fatalf("invalid provider type %s", typ)
}
log = api.NewLogger("modb")
log = util.NewLogger("modb")
conn.Logger(log.TRACE)
// prepare device

View file

@ -7,7 +7,7 @@ import (
"sync"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
@ -18,7 +18,7 @@ const (
// MqttClient is a paho publisher
type MqttClient struct {
log *api.Logger
log *util.Logger
mux sync.Mutex
Client mqtt.Client
broker string
@ -34,7 +34,7 @@ func NewMqttClient(
clientID string,
qos byte,
) *MqttClient {
log := api.NewLogger("mqtt")
log := util.NewLogger("mqtt")
log.INFO.Printf("connecting %s at %s", clientID, broker)
mc := &MqttClient{
@ -160,7 +160,7 @@ func (m *MqttClient) formatValue(param, message string, v interface{}) (string,
return fmt.Sprintf("%v", v), nil
}
return replaceFormatted(message, map[string]interface{}{
return util.ReplaceFormatted(message, map[string]interface{}{
param: v,
})
}
@ -213,7 +213,7 @@ func (m *MqttClient) WaitForToken(token mqtt.Token) {
}
type msgHandler struct {
log *api.Logger
log *util.Logger
once sync.Once
mux sync.Mutex
updated time.Time
@ -292,5 +292,5 @@ func (h *msgHandler) boolGetter() (bool, error) {
return false, fmt.Errorf("%s outdated: %v", h.topic, elapsed.Truncate(time.Second))
}
return truish(string(h.payload)), nil
return util.Truish(string(h.payload)), nil
}

View file

@ -2,17 +2,18 @@ package provider
import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
type openWBStatusProvider struct {
plugged, charging BoolGetter
}
func openWBStatusFromConfig(log *api.Logger, other map[string]interface{}) StringGetter {
func openWBStatusFromConfig(log *util.Logger, other map[string]interface{}) StringGetter {
cc := struct {
Plugged, Charging Config
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
o := &openWBStatusProvider{
plugged: NewBoolGetterFromConfig(log, cc.Plugged),

View file

@ -3,7 +3,7 @@ package push
import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
// Sender implements message sending
@ -16,18 +16,18 @@ type EventTemplate struct {
Title, Msg string
}
var log = api.NewLogger("push")
var log = util.NewLogger("push")
// NewMessengerFromConfig creates a new messenger
func NewMessengerFromConfig(typ string, other map[string]interface{}) Sender {
switch strings.ToLower(typ) {
case "pushover":
var cc pushOverConfig
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewPushOverMessenger(cc.App, cc.Recipients)
case "telegram":
var cc telegramConfig
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
return NewTelegramMessenger(cc.Token, cc.Chats)
}

View file

@ -1,52 +0,0 @@
package push
import (
"errors"
"fmt"
"regexp"
"strings"
)
// Event is a notification event
type Event struct {
Event string
Attributes map[string]interface{}
}
// apply applies the event template to the content to produce the actual message
func (e Event) apply(template string) (string, error) {
return replaceFormatted(template, e.Attributes)
}
var re = regexp.MustCompile(`\${(\w+)(:([a-zA-Z0-9%.]+))?}`)
// 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) {
matches := re.FindAllStringSubmatch(s, -1)
for len(matches) > 0 {
for _, m := range matches {
key := m[1]
val, ok := kv[key]
if !ok {
return "", errors.New("could not find match for " + m[0])
}
// apply format
format := m[3]
if format != "" {
val = fmt.Sprintf(format, val)
}
// update string
literalMatch := m[0]
s = strings.ReplaceAll(s, literalMatch, fmt.Sprintf("%v", val))
}
// update matches
matches = re.FindAllStringSubmatch(s, -1)
}
return s, nil
}

View file

@ -1,5 +1,18 @@
package push
import "github.com/andig/evcc/util"
// Event is a notification event
type Event struct {
Event string
Attributes map[string]interface{}
}
// apply applies the event template to the content to produce the actual message
func (e Event) apply(template string) (string, error) {
return util.ReplaceFormatted(template, e.Attributes)
}
// Hub subscribes to event notifications and sends them to client devices
type Hub struct {
definitions map[string]EventTemplate

View file

@ -4,8 +4,8 @@ import (
"sync"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/core"
"github.com/andig/evcc/util"
influxdb "github.com/influxdata/influxdb1-client/v2"
)
@ -18,7 +18,7 @@ const (
// Influx is a influx publisher
type Influx struct {
sync.Mutex
log *api.Logger
log *util.Logger
client influxdb.Client
points []*influxdb.Point
pointsConf influxdb.BatchPointsConfig
@ -33,7 +33,7 @@ func NewInfluxClient(
user string,
password string,
) *Influx {
log := api.NewLogger("iflx")
log := util.NewLogger("iflx")
if database == "" {
log.FATAL.Fatal("missing database")

View file

@ -1,5 +1,5 @@
package server
import "github.com/andig/evcc/api"
import "github.com/andig/evcc/util"
var log = api.NewLogger("srvr")
var log = util.NewLogger("srvr")

View file

@ -1,4 +1,4 @@
package api
package util
import (
"github.com/mitchellh/mapstructure"

View file

@ -1,4 +1,4 @@
package provider
package util
import (
"errors"
@ -9,13 +9,13 @@ 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 {
// 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"
}
// formatValue will apply specific formatting in addition to standard sprintf
func formatValue(format string, val interface{}) string {
// FormatValue will apply specific formatting in addition to standard sprintf
func FormatValue(format string, val interface{}) string {
switch val := val.(type) {
case bool:
if format == "%d" {
@ -33,8 +33,8 @@ func formatValue(format string, val interface{}) string {
return fmt.Sprintf(format, val)
}
// replaceFormatted replaces all occurrences of ${key} with formatted val from the kv map
func replaceFormatted(s string, kv map[string]interface{}) (string, error) {
// ReplaceFormatted replaces all occurrences of ${key} with formatted val from the kv map
func ReplaceFormatted(s string, kv map[string]interface{}) (string, error) {
for m := re.FindStringSubmatch(s); m != nil; m = re.FindStringSubmatch(s) {
// find key and replacement value
val, ok := kv[m[1]]
@ -43,7 +43,7 @@ func replaceFormatted(s string, kv map[string]interface{}) (string, error) {
}
// update all literal matches
new := formatValue(m[3], val)
new := FormatValue(m[3], val)
s = strings.ReplaceAll(s, m[0], new)
}

View file

@ -1,4 +1,4 @@
package provider
package util
import (
"math"
@ -20,7 +20,7 @@ func TestTruish(t *testing.T) {
}
for _, c := range cases {
b := truish(c.k)
b := Truish(c.k)
if b != c.v {
t.Errorf("expected %v got %v", c.v, b)
}
@ -39,7 +39,7 @@ func TestReplace(t *testing.T) {
}
for _, c := range cases {
s, err := replaceFormatted(c.fmt, map[string]interface{}{
s, err := ReplaceFormatted(c.fmt, map[string]interface{}{
c.k: c.v,
})
@ -50,7 +50,7 @@ func TestReplace(t *testing.T) {
}
func TestReplaceMulti(t *testing.T) {
s, err := replaceFormatted("${foo}-${bar}", map[string]interface{}{
s, err := ReplaceFormatted("${foo}-${bar}", map[string]interface{}{
"foo": "bar",
"bar": "baz",
})
@ -61,7 +61,7 @@ func TestReplaceMulti(t *testing.T) {
}
func TestReplaceNoMatch(t *testing.T) {
s, err := replaceFormatted("${foo}", map[string]interface{}{
s, err := ReplaceFormatted("${foo}", map[string]interface{}{
"bar": "baz",
})

View file

@ -1,4 +1,4 @@
package api
package util
import (
"bytes"

View file

@ -1,4 +1,4 @@
package api
package util
import (
"io/ioutil"
@ -39,6 +39,16 @@ func Loggers(cb func(string, *Logger)) {
}
}
// LogLevel sets log level for all loggers
func LogLevel(level string) {
OutThreshold = LogLevelToThreshold(level)
LogThreshold = OutThreshold
Loggers(func(name string, logger *Logger) {
logger.SetStdoutThreshold(OutThreshold)
})
}
// LogLevelToThreshold converts log level string to a jww Threshold
func LogLevelToThreshold(level string) jww.Threshold {
switch strings.ToUpper(level) {

View file

@ -11,6 +11,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
)
const (
@ -45,7 +46,7 @@ type audiBatteryResponse struct {
// Audi is an api.Vehicle implementation for Audi cars
type Audi struct {
*embed
*api.HTTPHelper
*util.HTTPHelper
user, password, vin string
token string
tokenValid time.Time
@ -53,18 +54,18 @@ type Audi struct {
}
// NewAudiFromConfig creates a new vehicle
func NewAudiFromConfig(log *api.Logger, other map[string]interface{}) api.Vehicle {
func NewAudiFromConfig(log *util.Logger, other map[string]interface{}) api.Vehicle {
cc := struct {
Title string
Capacity int64
User, Password, VIN string
Cache time.Duration
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
v := &Audi{
embed: &embed{cc.Title, cc.Capacity},
HTTPHelper: api.NewHTTPHelper(api.NewLogger("audi")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("audi")),
user: cc.User,
password: cc.Password,
vin: cc.VIN,

View file

@ -11,6 +11,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
)
const (
@ -27,7 +28,7 @@ type bmwDynamicResponse struct {
// BMW is an api.Vehicle implementation for BMW cars
type BMW struct {
*embed
*api.HTTPHelper
*util.HTTPHelper
user, password, vin string
token string
tokenValid time.Time
@ -35,18 +36,18 @@ type BMW struct {
}
// NewBMWFromConfig creates a new vehicle
func NewBMWFromConfig(log *api.Logger, other map[string]interface{}) api.Vehicle {
func NewBMWFromConfig(log *util.Logger, other map[string]interface{}) api.Vehicle {
cc := struct {
Title string
Capacity int64
User, Password, VIN string
Cache time.Duration
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
v := &BMW{
embed: &embed{cc.Title, cc.Capacity},
HTTPHelper: api.NewHTTPHelper(api.NewLogger("bmw ")),
HTTPHelper: util.NewHTTPHelper(util.NewLogger("bmw ")),
user: cc.User,
password: cc.Password,
vin: cc.VIN,

View file

@ -4,10 +4,11 @@ import (
"strings"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
)
// NewFromConfig creates vehicle from configuration
func NewFromConfig(log *api.Logger, typ string, other map[string]interface{}) api.Vehicle {
func NewFromConfig(log *util.Logger, typ string, other map[string]interface{}) api.Vehicle {
var c api.Vehicle
switch strings.ToLower(typ) {

View file

@ -5,6 +5,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
"github.com/joeshaw/carwings"
)
@ -17,14 +18,14 @@ type Nissan struct {
}
// NewNissanFromConfig creates a new vehicle
func NewNissanFromConfig(log *api.Logger, other map[string]interface{}) api.Vehicle {
func NewNissanFromConfig(log *util.Logger, other map[string]interface{}) api.Vehicle {
cc := struct {
Title string
Capacity int64
User, Password, Region string
Cache time.Duration
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
if cc.Region == "" {
cc.Region = carwings.RegionEurope

View file

@ -5,6 +5,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
"github.com/jsgoecke/tesla"
)
@ -17,7 +18,7 @@ type Tesla struct {
}
// NewTeslaFromConfig creates a new Tesla vehicle
func NewTeslaFromConfig(log *api.Logger, other map[string]interface{}) api.Vehicle {
func NewTeslaFromConfig(log *util.Logger, other map[string]interface{}) api.Vehicle {
cc := struct {
Title string
Capacity int64
@ -26,7 +27,7 @@ func NewTeslaFromConfig(log *api.Logger, other map[string]interface{}) api.Vehic
VIN string
Cache time.Duration
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
client, err := tesla.NewClient(&tesla.Auth{
ClientID: cc.ClientID,

View file

@ -5,6 +5,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/util"
)
type embed struct {
@ -29,14 +30,14 @@ type Vehicle struct {
}
// NewConfigurableFromConfig creates a new Vehicle
func NewConfigurableFromConfig(log *api.Logger, other map[string]interface{}) api.Vehicle {
func NewConfigurableFromConfig(log *util.Logger, other map[string]interface{}) api.Vehicle {
cc := struct {
Title string
Capacity int64
Charge provider.Config
Cache time.Duration
}{}
api.DecodeOther(log, other, &cc)
util.DecodeOther(log, other, &cc)
getter := provider.NewFloatGetterFromConfig(log, cc.Charge)
if cc.Cache > 0 {