evcc-io/vehicle/renault/kamereon/api.go
Sam Feyaerts 709fc827e2
Renault: add SocLimiter (#25757)
Co-authored-by: andig <andi@evcc.io>
2025-12-11 21:26:30 +01:00

204 lines
5 KiB
Go

package kamereon
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/vehicle/renault/gigya"
"github.com/evcc-io/evcc/vehicle/renault/keys"
)
const (
ActionStart = "start"
ActionStop = "stop"
ActionResume = "resume"
)
type API struct {
*request.Helper
keys keys.ConfigServer
identity *gigya.Identity
login func() error
}
func NewAPI(log *util.Logger, keys keys.ConfigServer, identity *gigya.Identity, login func() error) *API {
v := &API{
Helper: request.NewHelper(log),
keys: keys,
identity: identity,
login: login,
}
v.Client.Transport = &AuthDecorator{
Login: v.login,
Keys: v.keys,
Identity: v.identity,
Base: v.Client.Transport,
}
return v
}
func (v *API) Accounts(personID string) ([]Account, error) {
uri := fmt.Sprintf("%s/commerce/v1/persons/%s", v.keys.Target, personID)
var res struct {
Accounts []Account `json:"accounts"`
}
err := v.GetJSON(uri, &res)
return res.Accounts, err
}
func (v *API) AccountID(personID, brand string) (string, error) {
accounts, err := v.Accounts(personID)
if err != nil {
return "", err
}
for _, account := range accounts {
if strings.Contains(strings.ToLower(account.AccountType), strings.ToLower(brand)) {
return account.AccountID, nil
}
}
return "", errors.New("account not found")
}
func (v *API) Vehicles(accountID string) ([]Vehicle, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/vehicles", v.keys.Target, accountID)
var res struct {
VehicleLinks []Vehicle `json:"vehicleLinks"`
}
err := v.GetJSON(uri, &res)
return res.VehicleLinks, err
}
func (v *API) BatteryStatus(accountID string, vin string) (BatteryStatus, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kca/car-adapter/v2/cars/%s/battery-status", v.keys.Target, accountID, vin)
var res DataEnvelope[BatteryStatus]
err := v.GetJSON(uri, &res)
return res.Data.Attributes, err
}
func (v *API) HvacStatus(accountID string, vin string) (HvacStatus, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kca/car-adapter/v1/cars/%s/hvac-status", v.keys.Target, accountID, vin)
var res DataEnvelope[HvacStatus]
err := v.GetJSON(uri, &res)
return res.Data.Attributes, err
}
func (v *API) Cockpit(accountID string, vin string) (Cockpit, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kca/car-adapter/v1/cars/%s/cockpit", v.keys.Target, accountID, vin)
var res DataEnvelope[Cockpit]
err := v.GetJSON(uri, &res)
return res.Data.Attributes, err
}
func (v *API) SocLevels(accountID string, vin string) (SocLevels, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kcm/v1/vehicles/%s/ev/soc-levels", v.keys.Target, accountID, vin)
var res SocLevels
err := v.GetJSON(uri, &res)
return res, err
}
func (v *API) Position(accountID string, vin string) (Position, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kca/car-adapter/v1/cars/%s/location", v.keys.Target, accountID, vin)
var res DataEnvelope[Position]
err := v.GetJSON(uri, &res)
return res.Data.Attributes, err
}
func (v *API) WakeUp(accountID string, vin string) (ChargeAction, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kcm/v1/vehicles/%s/charge/pause-resume", v.keys.Target, accountID, vin)
reqBody := map[string]any{
"data": ChargeAction{
Type: "ChargePauseResume",
Attributes: ChargeActionAttributes{
Action: ActionResume,
},
},
}
var res struct {
Data ChargeAction `json:"data"`
}
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(reqBody))
if err != nil {
return ChargeAction{}, err
}
err = v.DoJSON(req, &res)
return res.Data, err
}
func (v *API) WakeUpMy24(accountID string, vin string) (EvSettingsResponse, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kcm/v1/vehicles/%s/ev/settings", v.keys.Target, accountID, vin)
reqBody := EvSettingsRequest{
LastSettingsUpdateTimestamp: "2025-04-24T12:41:41.823Z",
DelegatedActivated: false,
ChargeModeRq: "SCHEDULED",
ChargeTimeStart: "21:00",
ChargeDuration: 1615,
PreconditioningTemperature: 20.0,
Programs: []any{},
}
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(reqBody))
if err != nil {
return EvSettingsResponse{}, err
}
var res EvSettingsResponse
err = v.DoJSON(req, &res)
return res, err
}
func (v *API) ChargeAction(accountID, action string, vin string) (ChargeAction, error) {
uri := fmt.Sprintf("%s/commerce/v1/accounts/%s/kamereon/kca/car-adapter/v1/cars/%s/actions/charging-start", v.keys.Target, accountID, vin)
reqBody := map[string]any{
"data": ChargeAction{
Type: "ChargingStart",
Attributes: ChargeActionAttributes{
Action: action,
},
},
}
var res struct {
Data ChargeAction `json:"data"`
}
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(reqBody))
if err != nil {
return ChargeAction{}, err
}
err = v.DoJSON(req, &res)
return res.Data, err
}