Add charger, meter and vehicle commands (#38)

This commit is contained in:
andig 2020-04-15 13:30:34 +02:00 • committed by GitHub
parent 9513e91e78
commit dde26c7940
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 268 additions and 38 deletions

66
cmd/charger.go Normal file
View file

@ -0,0 +1,66 @@
package cmd
import (
"fmt"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// chargerCmd represents the charger command
var chargerCmd = &cobra.Command{
Use: "charger [name]",
Short: "Query configured chargers",
Run: runCharger,
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.AddCommand(chargerCmd)
configureCommand(chargerCmd)
}
func runCharger(cmd *cobra.Command, args []string) {
level, _ := cmd.PersistentFlags().GetString("log")
configureLogging(level)
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config
conf := loadConfigFile(cfgFile)
// setup mqtt
if viper.Get("mqtt") != nil {
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
}
chargers := configureChargers(conf)
for name, v := range chargers {
if len(args) == 1 {
if target := args[0]; name != target {
if _, ok := chargers[target]; !ok {
log.FATAL.Fatalf("charger not found: %s", target)
}
continue
}
} else if len(chargers) != 1 {
fmt.Println(name)
}
if status, err := v.Status(); err != nil {
fmt.Printf("Status: %v\n", err)
} else {
fmt.Printf("Status: %s\n", status)
}
if enabled, err := v.Enabled(); err != nil {
fmt.Printf("Enabled: %v\n", err)
} else {
fmt.Printf("Enabled: %s\n", truefalse[enabled])
}
dumpAPIs(v)
}
}

43
cmd/dump.go Normal file
View file

@ -0,0 +1,43 @@
package cmd
import (
"fmt"
"github.com/andig/evcc/api"
)
var truefalse = map[bool]string{false: "false", true: "true"}
func dumpAPIs(v interface{}) {
if v, ok := v.(api.Meter); ok {
if power, err := v.CurrentPower(); err != nil {
fmt.Printf("Power: %v\n", err)
} else {
fmt.Printf("Power: %.0fW\n", power)
}
}
if v, ok := v.(api.MeterEnergy); ok {
if energy, err := v.TotalEnergy(); err != nil {
fmt.Printf("Energy: %v\n", err)
} else {
fmt.Printf("Energy: %.0fkWh\n", energy)
}
}
if v, ok := v.(api.ChargeRater); ok {
if energy, err := v.ChargedEnergy(); err != nil {
fmt.Printf("Charged: %v\n", err)
} else {
fmt.Printf("Charged: %.0fkWh\n", energy)
}
}
if v, ok := v.(api.ChargeTimer); ok {
if duration, err := v.ChargingTime(); err != nil {
fmt.Printf("Duration: %v\n", err)
} else {
fmt.Printf("Duration: %v\n", duration)
}
}
}

54
cmd/meter.go Normal file
View file

@ -0,0 +1,54 @@
package cmd
import (
"fmt"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// meterCmd represents the meter command
var meterCmd = &cobra.Command{
Use: "meter [name]",
Short: "Query configured meters",
Run: runMeter,
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.AddCommand(meterCmd)
configureCommand(meterCmd)
}
func runMeter(cmd *cobra.Command, args []string) {
level, _ := cmd.PersistentFlags().GetString("log")
configureLogging(level)
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config
conf := loadConfigFile(cfgFile)
// setup mqtt
if viper.Get("mqtt") != nil {
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
}
meters := configureMeters(conf)
for name, v := range meters {
if len(args) == 1 {
if target := args[0]; name != target {
if _, ok := meters[target]; !ok {
log.FATAL.Fatalf("meter not found: %s", target)
}
continue
}
} else if len(meters) != 1 {
fmt.Println(name)
}
dumpAPIs(v)
}
}

View file

@ -7,6 +7,7 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/core"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/spf13/cobra"
@ -26,46 +27,49 @@ var rootCmd = &cobra.Command{
Run: run,
}
func bind(flag string) {
if err := viper.BindPFlag(flag, rootCmd.PersistentFlags().Lookup(flag)); err != nil {
func bind(cmd *cobra.Command, flag string) {
if err := viper.BindPFlag(flag, cmd.PersistentFlags().Lookup(flag)); err != nil {
panic(err)
}
}
func configureCommand(cmd *cobra.Command) {
cmd.PersistentFlags().StringP(
"log", "l",
"error",
"Log level (fatal, error, warn, info, debug, trace)",
)
bind(cmd, "log")
cmd.PersistentFlags().StringVarP(&cfgFile,
"config", "c",
"",
"Config file (default \"~/evcc.yaml\" or \"/etc/evcc.yaml\")",
)
cmd.PersistentFlags().BoolP(
"help", "h",
false,
"Help for "+cmd.Name(),
)
}
func init() {
cobra.OnInitialize(initConfig)
configureCommand(rootCmd)
rootCmd.PersistentFlags().StringP(
"uri", "u",
"0.0.0.0:7070",
"Listen address",
)
bind("uri")
rootCmd.PersistentFlags().StringP(
"log", "l",
"info",
"Log level (fatal, error, warn, info, debug, trace)",
)
bind("log")
bind(rootCmd, "uri")
rootCmd.PersistentFlags().DurationP(
"interval", "i",
10*time.Second,
"Update interval",
)
bind("interval")
rootCmd.PersistentFlags().StringVarP(&cfgFile,
"config", "c",
"",
"Config file (default \"~/evcc.yaml\" or \"/etc/evcc.yaml\")",
)
rootCmd.PersistentFlags().BoolP(
"help", "h",
false,
"Help for "+rootCmd.Name(),
)
bind(rootCmd, "interval")
}
// initConfig reads in config file and ENV variables if set
@ -158,17 +162,8 @@ func run(cmd *cobra.Command, args []string) {
configureLogging(level)
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
var conf config
if cfgFile != "" {
log.INFO.Println("using config file", cfgFile)
if err := viper.UnmarshalExact(&conf); err != nil {
log.FATAL.Fatalf("config: failed parsing config file %s: %v", cfgFile, err)
}
} else {
log.FATAL.Fatal("missing evcc config")
}
// re-configure after reading config file
// load config and re-configure logging after reading config file
conf := loadConfigFile(cfgFile)
configureLogging(conf.Log)
go checkVersion()
@ -179,6 +174,11 @@ func run(cmd *cobra.Command, args []string) {
// setup messaging
notificationChan := configureMessengers(conf.Messaging)
// setup mqtt
if viper.Get("mqtt") != nil {
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
}
// setup loadpoints
loadPoints := loadConfig(conf, notificationChan)

View file

@ -8,7 +8,6 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/charger"
"github.com/andig/evcc/core"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/push"
"github.com/andig/evcc/vehicle"
"github.com/spf13/viper"
@ -95,10 +94,6 @@ func configureLoadPoint(lp *core.LoadPoint, lpc loadPointConfig, subv *viper.Vip
}
func loadConfig(conf config, eventsChan chan push.Event) (loadPoints []*core.LoadPoint) {
if viper.Get("mqtt") != nil {
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
}
meters := configureMeters(conf)
chargers := configureChargers(conf)
vehicles := configureVehicles(conf)
@ -148,3 +143,15 @@ func loadConfig(conf config, eventsChan chan push.Event) (loadPoints []*core.Loa
return
}
func loadConfigFile(cfgFile string) (conf config) {
if cfgFile != "" {
log.INFO.Println("using config file", cfgFile)
if err := viper.UnmarshalExact(&conf); err != nil {
log.FATAL.Fatalf("config: failed parsing config file %s: %v", cfgFile, err)
}
} else {
log.FATAL.Fatal("missing evcc config")
}
return
}

60
cmd/vehicle.go Normal file
View file

@ -0,0 +1,60 @@
package cmd
import (
"fmt"
"github.com/andig/evcc/provider"
"github.com/andig/evcc/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// vehicleCmd represents the vehicle command
var vehicleCmd = &cobra.Command{
Use: "vehicle [name]",
Short: "Query configured vehicles",
Run: runVehicle,
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.AddCommand(vehicleCmd)
configureCommand(vehicleCmd)
}
func runVehicle(cmd *cobra.Command, args []string) {
level, _ := cmd.PersistentFlags().GetString("log")
configureLogging(level)
log.INFO.Printf("evcc %s (%s)", server.Version, server.Commit)
// load config
conf := loadConfigFile(cfgFile)
// setup mqtt
if viper.Get("mqtt") != nil {
provider.MQTT = provider.NewMqttClient(conf.Mqtt.Broker, conf.Mqtt.User, conf.Mqtt.Password, clientID(), 1)
}
vehicles := configureVehicles(conf)
for name, v := range vehicles {
if len(args) == 1 {
if target := args[0]; name != target {
if _, ok := vehicles[target]; !ok {
log.FATAL.Fatalf("charger not found: %s", target)
}
continue
}
} else if len(vehicles) != 1 {
fmt.Println(name)
}
if soc, err := v.ChargeState(); err != nil {
fmt.Printf("State: %v\n", err)
} else {
fmt.Printf("State: %.0f%%\n", soc)
}
dumpAPIs(v)
}
}