201 lines
5.7 KiB
Go
201 lines
5.7 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/evcc-io/evcc/charger/easee"
|
|
"github.com/evcc-io/evcc/util"
|
|
"github.com/evcc-io/evcc/util/request"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
var easeeOcppCmd = &cobra.Command{
|
|
Use: "easee-ocpp",
|
|
Short: "Manage Easee local OCPP configuration",
|
|
}
|
|
|
|
var easeeOcppEnableCmd = &cobra.Command{
|
|
Use: "enable",
|
|
Short: "Enable local OCPP on Easee charger",
|
|
Run: runEaseeOcppEnable,
|
|
}
|
|
|
|
var easeeOcppDisableCmd = &cobra.Command{
|
|
Use: "disable",
|
|
Short: "Disable local OCPP on Easee charger",
|
|
Run: runEaseeOcppDisable,
|
|
}
|
|
|
|
var easeeOcppStatusCmd = &cobra.Command{
|
|
Use: "status",
|
|
Short: "Show Easee local OCPP configuration",
|
|
Run: runEaseeOcppStatus,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(easeeOcppCmd)
|
|
easeeOcppCmd.AddCommand(easeeOcppEnableCmd)
|
|
easeeOcppCmd.AddCommand(easeeOcppDisableCmd)
|
|
easeeOcppCmd.AddCommand(easeeOcppStatusCmd)
|
|
|
|
easeeOcppCmd.PersistentFlags().String("user", "", "Easee account email")
|
|
easeeOcppCmd.PersistentFlags().String("password", "", "Easee account password")
|
|
easeeOcppCmd.PersistentFlags().String("charger", "", "Easee charger serial number")
|
|
|
|
_ = easeeOcppCmd.MarkPersistentFlagRequired("user")
|
|
_ = easeeOcppCmd.MarkPersistentFlagRequired("password")
|
|
_ = easeeOcppCmd.MarkPersistentFlagRequired("charger")
|
|
|
|
easeeOcppEnableCmd.Flags().String("url", "", "OCPP Central System URL (e.g. ws://192.168.1.100:8887/)")
|
|
_ = easeeOcppEnableCmd.MarkFlagRequired("url")
|
|
}
|
|
|
|
type localOcppConnectionDetails struct {
|
|
ConnectivityMode string `json:"connectivityMode"`
|
|
WebsocketConnectionArgs *localOcppWebsocketArgs `json:"websocketConnectionArgs,omitempty"`
|
|
}
|
|
|
|
type localOcppWebsocketArgs struct {
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
type localOcppVersionResponse struct {
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
type localOcppApplyRequest struct {
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
type localOcppStatusResponse struct {
|
|
ConnectivityMode string `json:"connectivityMode"`
|
|
ChargePointID string `json:"chargePointId"`
|
|
WebsocketConnectionArgs *localOcppWebsocketArgs `json:"websocketConnectionArgs"`
|
|
}
|
|
|
|
func easeeOcppClient(user, password string) (*request.Helper, error) {
|
|
log := util.NewLogger("easee-ocpp")
|
|
log.Redact(user, password)
|
|
|
|
ts, err := easee.TokenSource(log, user, password)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("authentication failed: %w", err)
|
|
}
|
|
|
|
client := request.NewHelper(log)
|
|
client.Client.Transport = &oauth2.Transport{
|
|
Source: ts,
|
|
Base: client.Client.Transport,
|
|
}
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func easeeOcppApplyConfig(client *request.Helper, serial string, details localOcppConnectionDetails) error {
|
|
uri := fmt.Sprintf("%s/v1/connection-details/%s", easee.LocalOcppAPI, serial)
|
|
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(details), request.JSONEncoding)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var version localOcppVersionResponse
|
|
if err := client.DoJSON(req, &version); err != nil {
|
|
return fmt.Errorf("storing config: %w", err)
|
|
}
|
|
|
|
apply := localOcppApplyRequest{Version: version.Version}
|
|
uri = fmt.Sprintf("%s/v1/connections/chargers/%s", easee.LocalOcppAPI, serial)
|
|
req, err = request.New(http.MethodPost, uri, request.MarshalJSON(apply), request.JSONEncoding)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := client.DoBody(req); err != nil {
|
|
return fmt.Errorf("applying config: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runEaseeOcppEnable(cmd *cobra.Command, args []string) {
|
|
user, _ := cmd.Flags().GetString("user")
|
|
password, _ := cmd.Flags().GetString("password")
|
|
charger, _ := cmd.Flags().GetString("charger")
|
|
|
|
client, err := easeeOcppClient(user, password)
|
|
if err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
ocppURL, _ := cmd.Flags().GetString("url")
|
|
|
|
details := localOcppConnectionDetails{
|
|
ConnectivityMode: "DualProtocol",
|
|
WebsocketConnectionArgs: &localOcppWebsocketArgs{URL: ocppURL},
|
|
}
|
|
|
|
if err := easeeOcppApplyConfig(client, charger, details); err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("Local OCPP enabled for charger %s\n", charger)
|
|
fmt.Printf("OCPP Central System URL: %s\n", ocppURL)
|
|
}
|
|
|
|
func runEaseeOcppDisable(cmd *cobra.Command, args []string) {
|
|
user, _ := cmd.Flags().GetString("user")
|
|
password, _ := cmd.Flags().GetString("password")
|
|
charger, _ := cmd.Flags().GetString("charger")
|
|
|
|
client, err := easeeOcppClient(user, password)
|
|
if err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
// GET current config, strip charger-appended serial from URL, set OcppOff
|
|
uri := fmt.Sprintf("%s/v1/connection-details/%s", easee.LocalOcppAPI, charger)
|
|
|
|
var current localOcppConnectionDetails
|
|
if err := client.GetJSON(uri, ¤t); err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
current.ConnectivityMode = "OcppOff"
|
|
if current.WebsocketConnectionArgs != nil {
|
|
current.WebsocketConnectionArgs.URL = strings.TrimSuffix(current.WebsocketConnectionArgs.URL, charger)
|
|
}
|
|
|
|
if err := easeeOcppApplyConfig(client, charger, current); err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("Local OCPP disabled for charger %s\n", charger)
|
|
}
|
|
|
|
func runEaseeOcppStatus(cmd *cobra.Command, args []string) {
|
|
user, _ := cmd.Flags().GetString("user")
|
|
password, _ := cmd.Flags().GetString("password")
|
|
charger, _ := cmd.Flags().GetString("charger")
|
|
|
|
client, err := easeeOcppClient(user, password)
|
|
if err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
uri := fmt.Sprintf("%s/v1/connection-details/%s", easee.LocalOcppAPI, charger)
|
|
|
|
var status localOcppStatusResponse
|
|
if err := client.GetJSON(uri, &status); err != nil {
|
|
log.FATAL.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("Charger: %s\n", charger)
|
|
fmt.Printf("Connectivity mode: %s\n", status.ConnectivityMode)
|
|
fmt.Printf("Charge point ID: %s\n", status.ChargePointID)
|
|
if status.WebsocketConnectionArgs != nil {
|
|
fmt.Printf("OCPP URL: %s\n", status.WebsocketConnectionArgs.URL)
|
|
}
|
|
}
|