Nissan: add start/stop actions (#1366)

This commit is contained in:
andig 2021-08-16 12:00:13 +02:00 • committed by GitHub
parent 363c7b8c94
commit edc1b3efc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 41 deletions

View file

@ -7,7 +7,6 @@ import (
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/andig/evcc/vehicle/kamereon"
"github.com/andig/evcc/vehicle/nissan"
)
@ -22,7 +21,7 @@ import (
// Nissan is an api.Vehicle implementation for Nissan cars
type Nissan struct {
*embed
*kamereon.Provider
*nissan.Provider
}
func init() {
@ -64,7 +63,7 @@ func NewNissanFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
}
v.Provider = kamereon.NewProvider(api.Battery, cc.Cache)
v.Provider = nissan.NewProvider(api, cc.Cache)
return v, err
}

View file

@ -4,13 +4,11 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
"github.com/andig/evcc/util/request"
"github.com/andig/evcc/vehicle/kamereon"
"golang.org/x/oauth2"
)
@ -65,12 +63,14 @@ func (v *API) Vehicles() ([]string, error) {
return vehicles, err
}
const timeFormat = "2006-01-02T15:04:05Z"
// Battery provides battery api response
func (v *API) Battery() (kamereon.Response, error) {
func (v *API) Battery() (Response, error) {
// request battery status
uri := fmt.Sprintf("%s/v1/cars/%s/battery-status", CarAdapterBaseURL, v.VIN)
var res kamereon.Response
var res Response
err := v.GetJSON(uri, &res)
var ts time.Time
@ -111,12 +111,17 @@ func (v *API) Battery() (kamereon.Response, error) {
func (v *API) refreshRequest() error {
uri := fmt.Sprintf("%s/v1/cars/%s/actions/refresh-battery-status", CarAdapterBaseURL, v.VIN)
data := strings.NewReader(`{"data": {"type": "RefreshBatteryStatus"}}`)
req, err := request.New(http.MethodPost, uri, data, map[string]string{
data := Request{
Data: Payload{
Type: "RefreshBatteryStatus",
},
}
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), map[string]string{
"Content-Type": "application/vnd.api+json",
})
var res kamereon.Response
var res Response
if err == nil {
err = v.DoJSON(req, &res)
}
@ -132,3 +137,35 @@ func (v *API) refreshRequest() error {
return err
}
type Action string
const (
ActionChargeStart Action = "start"
ActionChargeStop Action = "stop"
)
// ChargingAction provides actions/charging-start api response
func (v *API) ChargingAction(action Action) (Response, error) {
uri := fmt.Sprintf("%s/v1/cars/%s/actions/charging-start", CarAdapterBaseURL, v.VIN)
data := Request{
Data: Payload{
Type: "ChargingStart",
Attributes: map[string]interface{}{
"action": action,
},
},
}
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), map[string]string{
"Content-Type": "application/vnd.api+json",
})
var res Response
if err == nil {
err = v.DoJSON(req, &res)
}
return res, err
}

View file

@ -1,4 +1,4 @@
package kamereon
package nissan
import (
"time"
@ -7,42 +7,22 @@ import (
"github.com/andig/evcc/provider"
)
// Response structure for kamereon api
type Response struct {
Data data `json:"data"`
}
type data struct {
Type, ID string // battery refresh
Attributes attributes `json:"attributes"`
}
type attributes struct {
Timestamp string `json:"timestamp"`
ChargingStatus float32 `json:"chargingStatus"`
InstantaneousPower int `json:"instantaneousPower"`
RangeHvacOff int `json:"rangeHvacOff"` // Nissan
BatteryAutonomy int `json:"batteryAutonomy"` // Renault
BatteryLevel int `json:"batteryLevel"`
BatteryCapacity int `json:"batteryCapacity"` // Nissan
BatteryTemperature int `json:"batteryTemperature"`
PlugStatus int `json:"plugStatus"`
LastUpdateTime string `json:"lastUpdateTime"`
ChargePower int `json:"chargePower"`
RemainingTime *int `json:"chargingRemainingTime"`
}
// Provider is a kamereon provider
type Provider struct {
apiG func() (interface{}, error)
apiG func() (interface{}, error)
action func(value Action) error
}
// NewProvider returns a kamereon provider
func NewProvider(respG func() (Response, error), cache time.Duration) *Provider {
func NewProvider(api *API, cache time.Duration) *Provider {
return &Provider{
apiG: provider.NewCached(func() (interface{}, error) {
return respG()
return api.Battery()
}, cache).InterfaceGetter(),
action: func(value Action) error {
_, err := api.ChargingAction(value)
return err
},
}
}
@ -109,3 +89,17 @@ func (v *Provider) FinishTime() (time.Time, error) {
return time.Time{}, err
}
var _ api.VehicleStartCharge = (*Provider)(nil)
// StartCharge implements the api.VehicleStartCharge interface
func (v *Provider) StartCharge() error {
return v.action(ActionChargeStart)
}
var _ api.VehicleStopCharge = (*Provider)(nil)
// StopCharge implements the api.VehicleStopCharge interface
func (v *Provider) StopCharge() error {
return v.action(ActionChargeStop)
}

View file

@ -14,8 +14,6 @@ const (
UserBaseURL = "https://nci-bff-web-prod.apps.eu.kamereon.io/bff-web"
)
const timeFormat = "2006-01-02T15:04:05Z"
type Auth struct {
AuthID string `json:"authId"`
Template string `json:"template"`
@ -50,3 +48,36 @@ type Vehicle struct {
ModelName string
PictureURL string
}
// Request structure for kamereon api
type Request struct {
Data Payload `json:"data"`
}
type Payload struct {
Type string `json:"type"`
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Response structure for kamereon api
type Response struct {
Data struct {
Type, ID string // battery refresh
Attributes attributes `json:"attributes"`
} `json:"data"`
}
type attributes struct {
Timestamp string `json:"timestamp"`
ChargingStatus float32 `json:"chargingStatus"`
InstantaneousPower int `json:"instantaneousPower"`
RangeHvacOff int `json:"rangeHvacOff"` // Nissan
BatteryAutonomy int `json:"batteryAutonomy"` // Renault
BatteryLevel int `json:"batteryLevel"`
BatteryCapacity int `json:"batteryCapacity"` // Nissan
BatteryTemperature int `json:"batteryTemperature"`
PlugStatus int `json:"plugStatus"`
LastUpdateTime string `json:"lastUpdateTime"`
ChargePower int `json:"chargePower"`
RemainingTime *int `json:"chargingRemainingTime"`
}