Add OpenEVSE chargers (#4462)
This commit is contained in:
parent
1239ec1255
commit
8b88693d40
16 changed files with 5026 additions and 1 deletions
259
charger/openevse.go
Normal file
259
charger/openevse.go
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
package charger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/charger/openevse"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
)
|
||||
|
||||
// OpenEVSE charger implementation
|
||||
type OpenEVSE struct {
|
||||
uri string
|
||||
api *openevse.ClientWithResponses
|
||||
helper *request.Helper
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("openevse", NewOpenEVSEFromConfig)
|
||||
}
|
||||
|
||||
// go:generate go run ../cmd/tools/decorate.go -f decorateOpenEVSE -b ""*OpenEVSE" -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
|
||||
|
||||
// NewOpenEVSEFromConfig creates a go-e charger from generic config
|
||||
func NewOpenEVSEFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
cc := struct {
|
||||
URI string
|
||||
User string
|
||||
Password string
|
||||
Timeout time.Duration
|
||||
}{
|
||||
Timeout: request.Timeout,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cc.URI == "" {
|
||||
return nil, errors.New("missing uri")
|
||||
}
|
||||
|
||||
return NewOpenEVSE(cc.URI, cc.User, cc.Password, cc.Timeout)
|
||||
}
|
||||
|
||||
// NewOpenEVSE creates OpenEVSE charger
|
||||
func NewOpenEVSE(uri, user, password string, timeout time.Duration) (api.Charger, error) {
|
||||
log := util.NewLogger("openevse").Redact(user, password)
|
||||
c := &OpenEVSE{
|
||||
helper: request.NewHelper(log),
|
||||
uri: uri,
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
options := []openevse.ClientOption{openevse.WithHTTPClient(c.helper.Client)}
|
||||
|
||||
if user != "" && password != "" {
|
||||
basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(user, password)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
options = append(options, openevse.WithRequestEditorFn(basicAuthProvider.Intercept))
|
||||
}
|
||||
|
||||
var err error
|
||||
c.api, err = openevse.NewClientWithResponses(uri, options...)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
if err := c.hasPhaseSwitchCapabilities(); err == nil {
|
||||
phases1p3p = c.phases1p3p
|
||||
|
||||
// disable EVSE's own 1/3-phase auto-switching
|
||||
if err := c.rapiCommand("$S8 0"); err != nil {
|
||||
return c, err
|
||||
}
|
||||
}
|
||||
|
||||
return decorateOpenEVSE(c, phases1p3p), err
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) requestContextWithTimeout() (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) hasPhaseSwitchCapabilities() error {
|
||||
return c.rapiCommand("$G7")
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) rapiCommand(command string) error {
|
||||
var res struct {
|
||||
Cmd, Ret string
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/r?json=1&rapi=%s", c.uri, url.QueryEscape(command))
|
||||
|
||||
err := c.helper.GetJSON(uri, &res)
|
||||
if err == nil && !strings.HasPrefix(res.Ret, "$OK") {
|
||||
err = fmt.Errorf("rapi command failed: %s", res.Ret)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) SetManualOverride(enable bool) error {
|
||||
state := "disabled"
|
||||
if enable {
|
||||
state = "active"
|
||||
}
|
||||
|
||||
data := openevse.SetManualOverrideJSONRequestBody{
|
||||
State: &state,
|
||||
}
|
||||
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
_, err := c.api.SetManualOverrideWithResponse(ctx, data)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) Status() (api.ChargeStatus, error) {
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
res, err := c.api.GetStatusWithResponse(ctx)
|
||||
if err != nil {
|
||||
return api.StatusNone, err
|
||||
}
|
||||
|
||||
/*
|
||||
0: "unknown",
|
||||
1: "not connected",
|
||||
2: "connected",
|
||||
3: "charging",
|
||||
4: "vent required",
|
||||
5: "diode check failed",
|
||||
6: "gfci fault",
|
||||
7: "no ground",
|
||||
8: "stuck relay",
|
||||
9: "gfci self-test failure",
|
||||
10: "over temperature",
|
||||
11: "over current",
|
||||
254: "sleeping",
|
||||
255: "disabled"
|
||||
*/
|
||||
|
||||
switch state := *res.JSON200.State; state {
|
||||
case 1:
|
||||
return api.StatusA, nil
|
||||
case 2, 254, 255:
|
||||
if connected := *res.JSON200.Vehicle != 0; connected {
|
||||
return api.StatusB, nil
|
||||
}
|
||||
return api.StatusA, nil
|
||||
case 3:
|
||||
return api.StatusC, nil
|
||||
case 4:
|
||||
return api.StatusD, nil
|
||||
case 5, 6, 7, 8, 9, 10, 11:
|
||||
return api.StatusF, nil
|
||||
default:
|
||||
return api.StatusNone, fmt.Errorf("unknown EVSE state: %d", state)
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (c *OpenEVSE) Enabled() (bool, error) {
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
overrideResp, err := c.api.GetManualOverrideWithResponse(ctx)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if overrideResp.JSON200 != nil && overrideResp.JSON200.State != nil {
|
||||
switch *overrideResp.JSON200.State {
|
||||
case "disabled":
|
||||
return false, nil
|
||||
case "enabled", "active":
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("unknown EVSE state: %s", *overrideResp.JSON200.State)
|
||||
}
|
||||
|
||||
// Enable implements the api.Charger interface
|
||||
func (c *OpenEVSE) Enable(enable bool) error {
|
||||
return c.SetManualOverride(enable)
|
||||
}
|
||||
|
||||
// MaxCurrent implements the api.Charger interface
|
||||
func (c *OpenEVSE) MaxCurrent(current int64) error {
|
||||
cur := int(current)
|
||||
data := openevse.SetManualOverrideJSONRequestBody{
|
||||
ChargeCurrent: &cur,
|
||||
}
|
||||
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := c.api.SetManualOverrideWithResponse(ctx, data)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ api.ChargeRater = (*OpenEVSE)(nil)
|
||||
|
||||
// ChargedEnergy implements the api.ChargeRater interface
|
||||
func (c *OpenEVSE) ChargedEnergy() (float64, error) {
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
resp, err := c.api.GetStatusWithResponse(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return float64(*resp.JSON200.Wattsec) / 3600 / 1e3, nil
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*OpenEVSE)(nil)
|
||||
|
||||
// TotalEnergy implements the api.MeterEnergy interface
|
||||
func (c *OpenEVSE) TotalEnergy() (float64, error) {
|
||||
ctx, cancel := c.requestContextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
resp, err := c.api.GetStatusWithResponse(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return float64(*resp.JSON200.Watthour) / 1e3, nil
|
||||
}
|
||||
|
||||
// phases1p3p implements the api.ChargePhases interface
|
||||
func (c *OpenEVSE) phases1p3p(phases int) error {
|
||||
var set3p int
|
||||
if phases == 3 {
|
||||
set3p = 1
|
||||
}
|
||||
|
||||
return c.rapiCommand(fmt.Sprintf("$S7 %d", set3p))
|
||||
}
|
||||
3490
charger/openevse/api.go
Normal file
3490
charger/openevse/api.go
Normal file
File diff suppressed because it is too large
Load diff
644
charger/openevse/api.yaml
Normal file
644
charger/openevse/api.yaml
Normal file
|
|
@ -0,0 +1,644 @@
|
|||
openapi: 3.0.2
|
||||
info:
|
||||
title: OpenEVSE WiFi API
|
||||
description: |
|
||||
The API for the OpenEVSE WiFi module
|
||||
version: "1.0"
|
||||
contact:
|
||||
email: jeremy@bigjungle.net
|
||||
name: Jeremy Poulter
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
servers:
|
||||
- url: "{server}"
|
||||
variables:
|
||||
server:
|
||||
default: "http://openevse.local"
|
||||
- url: "http://localhost:8080"
|
||||
paths:
|
||||
/status:
|
||||
get:
|
||||
operationId: getStatus
|
||||
summary: Get the EVSE status
|
||||
description: |
|
||||
The status endpoint can be called to get the status of the EVSE.
|
||||
|
||||
While it is posible to poll this endpoint, the recomendatoin is to retrieve the initial
|
||||
state then use the [/ws](#statusUpdates)
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Status.yaml
|
||||
examples:
|
||||
EVSE Status:
|
||||
value:
|
||||
mode: STA
|
||||
wifi_client_connected: 1
|
||||
eth_connected: 0
|
||||
net_connected: 1
|
||||
srssi: -73
|
||||
ipaddress: 192.168.1.43
|
||||
emoncms_connected: 1
|
||||
packets_sent: 22307
|
||||
packets_success: 22290
|
||||
mqtt_connected: 1
|
||||
ohm_hour: NotConnected
|
||||
free_heap: 203268
|
||||
comm_sent: 335139
|
||||
comm_success: 335139
|
||||
rapi_connected: 1
|
||||
amp: 0
|
||||
pilot: 32
|
||||
temp1: 282
|
||||
temp2: -2560
|
||||
temp3: -2560
|
||||
state: 254
|
||||
elapsed: 3473
|
||||
wattsec: 22493407
|
||||
watthour: 51536
|
||||
gfcicount: 0
|
||||
nogndcount: 0
|
||||
stuckcount: 0
|
||||
divertmode: 1
|
||||
solar: 390
|
||||
grid_ie: 0
|
||||
charge_rate: 7
|
||||
divert_update: 0
|
||||
ota_update: 0
|
||||
time: "2020-05-12T17:53:48Z"
|
||||
offset: "+0000"
|
||||
tags:
|
||||
- Status
|
||||
/ws:
|
||||
get:
|
||||
operationId: statusUpdates
|
||||
summary: EVSE status updates
|
||||
description: |
|
||||
As the state changes on the EVSE a websocket frame will be sent over the socket.
|
||||
The frame will contain a JSON document conntaining only the updated state.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Status.yaml
|
||||
tags:
|
||||
- Status
|
||||
/config:
|
||||
get:
|
||||
operationId: getConfig
|
||||
summary: Get the EVSE configuration
|
||||
description: ""
|
||||
tags:
|
||||
- Config
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Config.yaml
|
||||
examples: {}
|
||||
post:
|
||||
operationId: updateConfig
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/UpdateSuccessful"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Config.yaml
|
||||
examples:
|
||||
Update EmonCMS setting:
|
||||
value:
|
||||
emoncms_enabled: true
|
||||
emoncms_server: "http://emoncms.org"
|
||||
emoncms_node: openevse-a7d4
|
||||
emoncms_apikey: emoncmskey
|
||||
emoncms_fingerprint: ""
|
||||
Configure Solar divert:
|
||||
value:
|
||||
divert_enabled: true
|
||||
divert_attack_smoothing_factor: 0.4
|
||||
divert_decay_smoothing_factor: 0.05
|
||||
divert_min_charge_time: 60
|
||||
Set normal charging mode:
|
||||
value:
|
||||
charge_mode: fast
|
||||
Set Eco mode:
|
||||
value:
|
||||
charge_mode: eco
|
||||
Configure Tesla credentials:
|
||||
value:
|
||||
tesla_enabled: true
|
||||
tesla_access_token: qts-1234.......
|
||||
tesla_refresh_token: abcd.......
|
||||
tesla_created_at: 1623358948
|
||||
tesla_expires_in: 3888000
|
||||
Select Tesla vehicle:
|
||||
value:
|
||||
tesla_vehicle_id: "2238974987235987"
|
||||
summary: Update the EVSE configuration
|
||||
tags:
|
||||
- Config
|
||||
/override:
|
||||
description: Manual override can be used to override a charging timer or to immediately start a charge if the EVSE is in sleeping state.
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: Manual overide is active
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Properties.yaml
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
operationId: getManualOverride
|
||||
tags:
|
||||
- Manual Override
|
||||
summary: Get the Manual Override status
|
||||
description: Returns the current state of the manual override.
|
||||
post:
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Properties.yaml
|
||||
examples:
|
||||
Force stop of charging:
|
||||
value:
|
||||
state: disabled
|
||||
example-1:
|
||||
value:
|
||||
state: active
|
||||
charge_current: 0
|
||||
max_current: 0
|
||||
energy_limit: 0
|
||||
time_limit: 0
|
||||
auto_release: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
operationId: setManualOverride
|
||||
tags:
|
||||
- Manual Override
|
||||
summary: Set the manual override
|
||||
patch:
|
||||
description: Toggle the manual override
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
operationId: toggleManualOverride
|
||||
tags:
|
||||
- Manual Override
|
||||
summary: Toggle the manual Override
|
||||
delete:
|
||||
description: Clears the manual override
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
operationId: clearManualOverride
|
||||
tags:
|
||||
- Manual Override
|
||||
summary: Clear the manual override
|
||||
/claims:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: ./models/Claim.yaml
|
||||
operationId: listClaims
|
||||
tags:
|
||||
- Claims
|
||||
summary: List EVSE claims
|
||||
"/claims/{client}":
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Properties.yaml
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
parameters: []
|
||||
operationId: getClaim
|
||||
tags:
|
||||
- Claims
|
||||
summary: Get EVSE claim information
|
||||
post:
|
||||
description: Make/Update a claim
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/Properties.yaml
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
operationId: setClaim
|
||||
summary: Make/Update an EVSE claim
|
||||
tags:
|
||||
- Claims
|
||||
delete:
|
||||
description: Release a claim
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
operationId: releaseClaim
|
||||
summary: Release an EVSE claim
|
||||
tags:
|
||||
- Claims
|
||||
parameters:
|
||||
- schema:
|
||||
type: integer
|
||||
name: client
|
||||
in: path
|
||||
required: true
|
||||
description: "The client ID, defined by [OpenEVSE](https://github.com/OpenEVSE/ESP32_WiFi_V4.x/blob/master/src/evse_man.h#L25)"
|
||||
/schedule:
|
||||
get:
|
||||
summary: List schedule events
|
||||
description: This will get a complete list of events in the schedule
|
||||
responses:
|
||||
"200":
|
||||
description: List of the schedule events
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ScheduleEvent"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
operationId: listSchedule
|
||||
tags:
|
||||
- Schedule
|
||||
post:
|
||||
operationId: updateSchedule
|
||||
description: Perform multiple event updates
|
||||
responses:
|
||||
"201":
|
||||
description: item created
|
||||
"400":
|
||||
description: "invalid input, object invalid"
|
||||
"409":
|
||||
description: an existing item already exists
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ScheduleEvent"
|
||||
examples:
|
||||
Single event:
|
||||
value:
|
||||
- id: 1
|
||||
state: active
|
||||
time: "14:15:22Z"
|
||||
days:
|
||||
- monday
|
||||
Daily Timer:
|
||||
value:
|
||||
- id: 1
|
||||
state: active
|
||||
days:
|
||||
- monday
|
||||
- tuesday
|
||||
- wednesday
|
||||
- thursday
|
||||
- friday
|
||||
- saturday
|
||||
- sunday
|
||||
time: "07:00:00"
|
||||
- id: 2
|
||||
state: disabled
|
||||
days:
|
||||
- monday
|
||||
- tuesday
|
||||
- wednesday
|
||||
- thursday
|
||||
- friday
|
||||
- saturday
|
||||
- sunday
|
||||
time: "10:00:00"
|
||||
description: Inventory item to add
|
||||
tags:
|
||||
- Schedule
|
||||
summary: Batch update schedule
|
||||
"/schedule/{id}":
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
description: Numeric ID of the event
|
||||
get:
|
||||
summary: Get event details
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/EvseState.yaml
|
||||
operationId: getScheduleEvent
|
||||
tags:
|
||||
- Schedule
|
||||
post:
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/UpdateSuccessful"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: ./models/EvseState.yaml
|
||||
description: ""
|
||||
operationId: setScheduleEvent
|
||||
tags:
|
||||
- Schedule
|
||||
summary: Update event details
|
||||
delete:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
examples: {}
|
||||
operationId: removeScheduleEvent
|
||||
tags:
|
||||
- Schedule
|
||||
summary: Remove event
|
||||
/logs:
|
||||
get:
|
||||
summary: Get event block information
|
||||
tags:
|
||||
- Event Log
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
min:
|
||||
type: integer
|
||||
max:
|
||||
type: integer
|
||||
operationId: getEventBlockInfo
|
||||
description: "Retrieve the start and end indexes of the log event blocks. Each log event block contains "
|
||||
parameters: []
|
||||
parameters: []
|
||||
"/logs/{index}":
|
||||
get:
|
||||
summary: Get log block events
|
||||
tags:
|
||||
- Event Log
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/LogEvent"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
operationId: getEventBlock
|
||||
description: ""
|
||||
parameters:
|
||||
- schema:
|
||||
type: integer
|
||||
name: index
|
||||
in: path
|
||||
required: true
|
||||
/tesla/vehicles:
|
||||
get:
|
||||
summary: Get Tesla vehicle list
|
||||
tags:
|
||||
- Tesla
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
description: ""
|
||||
type: object
|
||||
x-examples:
|
||||
example-1:
|
||||
count: 3
|
||||
vehicles:
|
||||
- id: "1492932278133304"
|
||||
name: AwesomeSAUCE
|
||||
- id: "1492931610165415"
|
||||
name: Herbie
|
||||
- id: "1492930973960452"
|
||||
name: "Life, the Universe, and Everything"
|
||||
properties:
|
||||
count:
|
||||
type: number
|
||||
vehicles:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
minLength: 1
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
required:
|
||||
- count
|
||||
- vehicles
|
||||
examples:
|
||||
example-1:
|
||||
value:
|
||||
count: 1
|
||||
vehicles:
|
||||
- id: "2238974987235987"
|
||||
name: My Tesla
|
||||
operationId: get-tesla-vehicles
|
||||
description: Once the Tesla account credentials have been configured via the `/config` API this endpoint will return a list of vehicles associated with the account. The ID of the vehicle to use for SoC/Range can then be set using `tesla_vehicle_id` on the `/config` endpoint.
|
||||
components:
|
||||
schemas:
|
||||
Message:
|
||||
title: Informational message
|
||||
type: object
|
||||
properties:
|
||||
msg:
|
||||
type: string
|
||||
description: The message
|
||||
ScheduleEvent:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
example: 1
|
||||
state:
|
||||
$ref: ./models/EvseState.yaml
|
||||
time:
|
||||
type: string
|
||||
format: time
|
||||
days:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- monday
|
||||
- tuesday
|
||||
- wednesday
|
||||
- thursday
|
||||
- friday
|
||||
- saturday
|
||||
- sunday
|
||||
required:
|
||||
- state
|
||||
- time
|
||||
- days
|
||||
title: ""
|
||||
LogEvent:
|
||||
title: LogEvent
|
||||
type: object
|
||||
x-examples:
|
||||
example-1:
|
||||
value:
|
||||
time: "2021-08-24T14:15:22Z"
|
||||
type: information
|
||||
managerState: active
|
||||
evseState: 1
|
||||
evseFlags: 123
|
||||
pilot: 32
|
||||
energy: 1234.5
|
||||
elapsed: 123456
|
||||
temperature: 35.4
|
||||
tempuratureMax: 50.4
|
||||
divertMode: 1
|
||||
properties:
|
||||
time:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- information
|
||||
- notification
|
||||
- warning
|
||||
managerState:
|
||||
$ref: ./models/EvseState.yaml
|
||||
evseState:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
evseFlags:
|
||||
type: integer
|
||||
format: int32
|
||||
pilot:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
energy:
|
||||
type: number
|
||||
format: double
|
||||
minimum: 0
|
||||
elapsed:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
temperature:
|
||||
type: number
|
||||
format: double
|
||||
tempuratureMax:
|
||||
type: number
|
||||
format: double
|
||||
divertMode:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 2
|
||||
exclusiveMaximum: false
|
||||
responses:
|
||||
UpdateSuccessful:
|
||||
description: Update successful
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
examples:
|
||||
Success message:
|
||||
value:
|
||||
msg: done
|
||||
NotFound:
|
||||
description: Example response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
examples:
|
||||
Not found:
|
||||
value:
|
||||
msg: Not found
|
||||
BadRequest:
|
||||
description: Example response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Message"
|
||||
examples:
|
||||
Bad JSON:
|
||||
value:
|
||||
msg: Could not parse JSON
|
||||
parameters: {}
|
||||
tags:
|
||||
- name: Claims
|
||||
- name: Config
|
||||
- name: Event Log
|
||||
- name: Manual Override
|
||||
- name: Schedule
|
||||
- name: Status
|
||||
- name: Tesla
|
||||
3
charger/openevse/generate.go
Normal file
3
charger/openevse/generate.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package openevse
|
||||
|
||||
// go:generate sh -c "oapi-codegen -package openevse -old-config-style -generate types,client api.yaml > api.go"
|
||||
13
charger/openevse/models/Claim.yaml
Normal file
13
charger/openevse/models/Claim.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
title: EVSE claim
|
||||
allOf:
|
||||
- type: object
|
||||
properties:
|
||||
client:
|
||||
type: integer
|
||||
description: "The client ID, defined by [OpenEVSE](src/evse_man.h#L25)"
|
||||
priority:
|
||||
type: integer
|
||||
description: "The priority of the claim, the higher the number the higher the priority"
|
||||
- $ref: ./Properties.yaml
|
||||
x-tags:
|
||||
- Claims
|
||||
352
charger/openevse/models/Config.yaml
Normal file
352
charger/openevse/models/Config.yaml
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
description: ""
|
||||
type: object
|
||||
x-examples:
|
||||
example-1:
|
||||
firmware: D7.1.2
|
||||
protocol: "-"
|
||||
espflash: 4194304
|
||||
espinfo: ESP32r1 2 core WiFi BLE BT
|
||||
buildenv: openevse_esp-wrover-kit
|
||||
version: 4.1.0.dev
|
||||
diode_check: true
|
||||
gfci_check: true
|
||||
ground_check: true
|
||||
relay_check: true
|
||||
vent_check: true
|
||||
temp_check: true
|
||||
service: 0
|
||||
scale: 220
|
||||
offset: 0
|
||||
max_current_soft: 32
|
||||
min_current_hard: 6
|
||||
max_current_hard: 32
|
||||
mqtt_supported_protocols:
|
||||
- mqtt
|
||||
- mqtts
|
||||
http_supported_protocols:
|
||||
- http
|
||||
- https
|
||||
ssid: wibble_ext
|
||||
pass: _DUMMY_PASSWORD
|
||||
www_username: ""
|
||||
www_password: ""
|
||||
hostname: openevse-a7d4
|
||||
sntp_hostname: pool.ntp.org
|
||||
time_zone: "Europe/London|GMT0BST,M3.5.0/1,M10.5.0"
|
||||
emoncms_server: "https://emoncms.org"
|
||||
emoncms_node: openevse-a7d4
|
||||
emoncms_apikey: _DUMMY_PASSWORD
|
||||
emoncms_fingerprint: ""
|
||||
mqtt_server: homeassistant.lan
|
||||
mqtt_port: 1883
|
||||
mqtt_topic: openevse
|
||||
mqtt_user: emonpi
|
||||
mqtt_pass: _DUMMY_PASSWORD
|
||||
mqtt_solar: ""
|
||||
mqtt_grid_ie: emon/test/grid_ie
|
||||
mqtt_vrms: emon/rightbar/voltage
|
||||
mqtt_vehicle_soc: ""
|
||||
mqtt_vehicle_range: ""
|
||||
mqtt_vehicle_eta: ""
|
||||
mqtt_announce_topic: openevse/announce/a7d4
|
||||
ocpp_server: ""
|
||||
ocpp_chargeBoxId: ""
|
||||
ocpp_idTag: ""
|
||||
tx_start_point: tx_pending
|
||||
ohm: ""
|
||||
divert_PV_ratio: 1.1
|
||||
divert_attack_smoothing_factor: 0.4
|
||||
divert_decay_smoothing_factor: 0.05
|
||||
divert_min_charge_time: 10
|
||||
tesla_access_token: _DUMMY_PASSWORD
|
||||
tesla_refresh_token: _DUMMY_PASSWORD
|
||||
tesla_created_at: 2479357952
|
||||
tesla_expires_in: 3888000
|
||||
tesla_vehicle_id: "142960157278"
|
||||
led_brightness: 51
|
||||
flags: 115467
|
||||
emoncms_enabled: true
|
||||
mqtt_enabled: true
|
||||
mqtt_reject_unauthorized: true
|
||||
ohm_enabled: false
|
||||
sntp_enabled: true
|
||||
tesla_enabled: true
|
||||
divert_enabled: true
|
||||
pause_uses_disabled: false
|
||||
mqtt_vehicle_range_miles: false
|
||||
ocpp_enabled: true
|
||||
ocpp_suspend_evse: true
|
||||
ocpp_energize_plug: true
|
||||
mqtt_protocol: mqtt
|
||||
charge_mode: fast
|
||||
examples:
|
||||
- firmware: D7.1.2
|
||||
protocol: "-"
|
||||
espflash: 4194304
|
||||
espinfo: ESP32r1 2 core WiFi BLE BT
|
||||
buildenv: openevse_esp-wrover-kit
|
||||
version: 4.1.0.dev
|
||||
diode_check: true
|
||||
gfci_check: true
|
||||
ground_check: true
|
||||
relay_check: true
|
||||
vent_check: true
|
||||
temp_check: true
|
||||
service: 0
|
||||
scale: 220
|
||||
offset: 0
|
||||
max_current_soft: 32
|
||||
min_current_hard: 6
|
||||
max_current_hard: 32
|
||||
mqtt_supported_protocols:
|
||||
- mqtt
|
||||
- mqtts
|
||||
http_supported_protocols:
|
||||
- http
|
||||
- https
|
||||
ssid: wibble_ext
|
||||
pass: _DUMMY_PASSWORD
|
||||
www_username: ""
|
||||
www_password: ""
|
||||
hostname: openevse-a7d4
|
||||
sntp_hostname: pool.ntp.org
|
||||
time_zone: "Europe/London|GMT0BST,M3.5.0/1,M10.5.0"
|
||||
emoncms_server: "https://emoncms.org"
|
||||
emoncms_node: openevse-a7d4
|
||||
emoncms_apikey: _DUMMY_PASSWORD
|
||||
emoncms_fingerprint: ""
|
||||
mqtt_server: homeassistant.lan
|
||||
mqtt_port: 1883
|
||||
mqtt_topic: openevse
|
||||
mqtt_user: emonpi
|
||||
mqtt_pass: _DUMMY_PASSWORD
|
||||
mqtt_solar: ""
|
||||
mqtt_grid_ie: emon/test/grid_ie
|
||||
mqtt_vrms: emon/rightbar/voltage
|
||||
mqtt_vehicle_soc: ""
|
||||
mqtt_vehicle_range: ""
|
||||
mqtt_vehicle_eta: ""
|
||||
mqtt_announce_topic: openevse/announce/a7d4
|
||||
ocpp_server: ""
|
||||
ocpp_chargeBoxId: ""
|
||||
ocpp_idTag: ""
|
||||
tx_start_point: tx_pending
|
||||
ohm: ""
|
||||
divert_PV_ratio: 1.1
|
||||
divert_attack_smoothing_factor: 0.4
|
||||
divert_decay_smoothing_factor: 0.05
|
||||
divert_min_charge_time: 10
|
||||
tesla_access_token: _DUMMY_PASSWORD
|
||||
tesla_refresh_token: _DUMMY_PASSWORD
|
||||
tesla_created_at: 2479357952
|
||||
tesla_expires_in: 3888000
|
||||
tesla_vehicle_id: "142960157278"
|
||||
led_brightness: 51
|
||||
flags: 115467
|
||||
emoncms_enabled: true
|
||||
mqtt_enabled: true
|
||||
mqtt_reject_unauthorized: true
|
||||
ohm_enabled: false
|
||||
sntp_enabled: true
|
||||
tesla_enabled: true
|
||||
divert_enabled: true
|
||||
pause_uses_disabled: false
|
||||
mqtt_vehicle_range_miles: false
|
||||
ocpp_enabled: true
|
||||
ocpp_suspend_evse: true
|
||||
ocpp_energize_plug: true
|
||||
mqtt_protocol: mqtt
|
||||
charge_mode: fast
|
||||
x-tags:
|
||||
- Config
|
||||
properties:
|
||||
firmware:
|
||||
type: string
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
protocol:
|
||||
type: string
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
espflash:
|
||||
type: number
|
||||
readOnly: true
|
||||
espinfo:
|
||||
type: string
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
buildenv:
|
||||
type: string
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
version:
|
||||
type: string
|
||||
minLength: 1
|
||||
readOnly: true
|
||||
diode_check:
|
||||
type: boolean
|
||||
gfci_check:
|
||||
type: boolean
|
||||
ground_check:
|
||||
type: boolean
|
||||
relay_check:
|
||||
type: boolean
|
||||
vent_check:
|
||||
type: boolean
|
||||
temp_check:
|
||||
type: boolean
|
||||
service:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 2
|
||||
scale:
|
||||
type: integer
|
||||
offset:
|
||||
type: integer
|
||||
max_current_soft:
|
||||
type: integer
|
||||
min_current_hard:
|
||||
type: integer
|
||||
readOnly: true
|
||||
max_current_hard:
|
||||
type: integer
|
||||
readOnly: true
|
||||
mqtt_supported_protocols:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
readOnly: true
|
||||
http_supported_protocols:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
readOnly: true
|
||||
ssid:
|
||||
type: string
|
||||
minLength: 1
|
||||
pass:
|
||||
type: string
|
||||
minLength: 1
|
||||
www_username:
|
||||
type: string
|
||||
www_password:
|
||||
type: string
|
||||
hostname:
|
||||
type: string
|
||||
minLength: 1
|
||||
sntp_hostname:
|
||||
type: string
|
||||
minLength: 1
|
||||
time_zone:
|
||||
type: string
|
||||
minLength: 1
|
||||
emoncms_server:
|
||||
type: string
|
||||
minLength: 1
|
||||
emoncms_node:
|
||||
type: string
|
||||
minLength: 1
|
||||
emoncms_apikey:
|
||||
type: string
|
||||
minLength: 1
|
||||
emoncms_fingerprint:
|
||||
type: string
|
||||
mqtt_server:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_port:
|
||||
type: integer
|
||||
mqtt_topic:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_user:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_pass:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_solar:
|
||||
type: string
|
||||
mqtt_grid_ie:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_vrms:
|
||||
type: string
|
||||
minLength: 1
|
||||
mqtt_vehicle_soc:
|
||||
type: string
|
||||
mqtt_vehicle_range:
|
||||
type: string
|
||||
mqtt_vehicle_eta:
|
||||
type: string
|
||||
mqtt_announce_topic:
|
||||
type: string
|
||||
minLength: 1
|
||||
ocpp_server:
|
||||
type: string
|
||||
ocpp_chargeBoxId:
|
||||
type: string
|
||||
ocpp_idTag:
|
||||
type: string
|
||||
tx_start_point:
|
||||
type: string
|
||||
minLength: 1
|
||||
ohm:
|
||||
type: string
|
||||
divert_PV_ratio:
|
||||
type: number
|
||||
divert_attack_smoothing_factor:
|
||||
type: number
|
||||
divert_decay_smoothing_factor:
|
||||
type: number
|
||||
divert_min_charge_time:
|
||||
type: number
|
||||
tesla_access_token:
|
||||
type: string
|
||||
minLength: 1
|
||||
tesla_refresh_token:
|
||||
type: string
|
||||
minLength: 1
|
||||
tesla_created_at:
|
||||
type: number
|
||||
tesla_expires_in:
|
||||
type: number
|
||||
tesla_vehicle_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
led_brightness:
|
||||
type: number
|
||||
flags:
|
||||
type: number
|
||||
emoncms_enabled:
|
||||
type: boolean
|
||||
mqtt_enabled:
|
||||
type: boolean
|
||||
mqtt_reject_unauthorized:
|
||||
type: boolean
|
||||
ohm_enabled:
|
||||
type: boolean
|
||||
sntp_enabled:
|
||||
type: boolean
|
||||
tesla_enabled:
|
||||
type: boolean
|
||||
divert_enabled:
|
||||
type: boolean
|
||||
pause_uses_disabled:
|
||||
type: boolean
|
||||
mqtt_vehicle_range_miles:
|
||||
type: boolean
|
||||
ocpp_enabled:
|
||||
type: boolean
|
||||
ocpp_suspend_evse:
|
||||
type: boolean
|
||||
ocpp_energize_plug:
|
||||
type: boolean
|
||||
mqtt_protocol:
|
||||
type: string
|
||||
minLength: 1
|
||||
charge_mode:
|
||||
type: string
|
||||
minLength: 1
|
||||
6
charger/openevse/models/EvseState.yaml
Normal file
6
charger/openevse/models/EvseState.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
title: EvseState
|
||||
type: string
|
||||
x-tags:
|
||||
- Claims
|
||||
- Status
|
||||
description: Either enable charging (`active`) or block charging (`disabled`)
|
||||
39
charger/openevse/models/Properties.yaml
Normal file
39
charger/openevse/models/Properties.yaml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
title: Properties
|
||||
type: object
|
||||
x-tags:
|
||||
- Claims
|
||||
description: ""
|
||||
examples: []
|
||||
properties:
|
||||
state:
|
||||
$ref: ./EvseState.yaml
|
||||
charge_current:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: Specify the active charge current in Amps
|
||||
max_current:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: Dynamically alter the max current while still allowing other claims to very the current via `charge_current` that can not exceede this value. This is primerialy designed for load sharing situations while still allowing things like PV divert to work so the charge current is the minimum of `charge_current` <= `max_current` <= configured soft limit <= hard coded limit
|
||||
energy_limit:
|
||||
type: integer
|
||||
minimum: 0
|
||||
format: int32
|
||||
description: |-
|
||||
Stop the charge after `energy_limit` Wh of energy have been transfered.
|
||||
|
||||
> Note: Not currently implemented
|
||||
time_limit:
|
||||
type: integer
|
||||
minimum: 0
|
||||
format: int32
|
||||
description: |-
|
||||
Stop the charge after the duration of the charging session has exceeded `time_limit` seconds
|
||||
|
||||
> Note: Not currently implemented
|
||||
auto_release:
|
||||
type: boolean
|
||||
description: |
|
||||
`true` if the manual override is auto-released when the vehicle is
|
||||
disconnected, `false` if manual override will persist after vehicle
|
||||
disconnection.
|
||||
136
charger/openevse/models/Status.yaml
Normal file
136
charger/openevse/models/Status.yaml
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
title: EVSE status
|
||||
type: object
|
||||
x-tags:
|
||||
- Status
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
description: The current mode of the EVSE
|
||||
wifi_client_connected:
|
||||
type: integer
|
||||
description: "`1`, WiFi is connected, `0` no WiFi connection"
|
||||
eth_connected:
|
||||
type: integer
|
||||
description: "`1`, Wired ethernet is connected, `0` no wired ethernet connection"
|
||||
net_connected:
|
||||
type: integer
|
||||
description: "`1`, network is connected, either wired or WiFi, `0` no network connection"
|
||||
srssi:
|
||||
type: integer
|
||||
description: WiFi RSSI signal strength
|
||||
ipaddress:
|
||||
type: string
|
||||
description: The current IP address of the WiFi module
|
||||
packets_sent:
|
||||
type: integer
|
||||
description: The number of posts sent to the EmonCMS server
|
||||
packets_success:
|
||||
type: integer
|
||||
description: The number of successful posts to the EmonCMS server
|
||||
emoncms_connected:
|
||||
type: integer
|
||||
description: "`1`, if connected to an EmonCMS server, `0` not connected"
|
||||
emoncms_message:
|
||||
type: string
|
||||
description: Last response message from the EmonCMS server
|
||||
mqtt_connected:
|
||||
type: integer
|
||||
description: "`1`, if connected to an EmonCMS server, `0` not connected"
|
||||
ohm_hour:
|
||||
type: string
|
||||
description: Last status message from the OhmHour connection
|
||||
free_heap:
|
||||
type: integer
|
||||
description: Number of bytes free in the ESP memory heap
|
||||
comm_sent:
|
||||
type: integer
|
||||
description: Number of RAPI messages sent
|
||||
comm_success:
|
||||
type: integer
|
||||
description: Number of successful RAPI messages
|
||||
rapi_connected:
|
||||
type: integer
|
||||
description: "`1`, if RAPI messages have successfully been sent to the OpenEVSE module, `0` not connected"
|
||||
evse_connected:
|
||||
type: integer
|
||||
description: "`1`, if the WiFi module has negociated a connection to the OpenEVSE module, `0` not connected"
|
||||
amp:
|
||||
type: number
|
||||
description: the value of the charge current in mA
|
||||
voltage:
|
||||
type: number
|
||||
description: "the charge voltage, read form the EVSE if supported, or supplied via MQTT or other external source"
|
||||
pilot:
|
||||
type: integer
|
||||
description: "the pilot value, in amps"
|
||||
temp:
|
||||
type: number
|
||||
description: "the derived temperature, in 1/10th °C"
|
||||
state:
|
||||
type: integer
|
||||
description: The EVSE status
|
||||
vehicle:
|
||||
type: integer
|
||||
description: "`1`, if a vehicle id connected to the EVSE, `0` not connected"
|
||||
colour:
|
||||
type: integer
|
||||
description: The LCD colour
|
||||
manual_override:
|
||||
type: integer
|
||||
description: "`1`, if the manual override is active, `0` default behaviour"
|
||||
elapsed:
|
||||
type: number
|
||||
description: "The duration of the current charge session, in seconds"
|
||||
wattsec:
|
||||
type: number
|
||||
description: "The amount of energy transfered in this charge session, in W/sec"
|
||||
watthour:
|
||||
type: integer
|
||||
description: "The total amount of energy transfered, in W/hour"
|
||||
gfcicount:
|
||||
type: integer
|
||||
description: Number of GFCI errors
|
||||
nogndcount:
|
||||
type: integer
|
||||
description: Number of no ground errors
|
||||
stuckcount:
|
||||
type: integer
|
||||
description: Number of stuck relay errors
|
||||
divertmode:
|
||||
type: integer
|
||||
description: "The PV divert mode, `1` normal, `2` Eco"
|
||||
service_level:
|
||||
type: integer
|
||||
description: The current service level
|
||||
minimum: 1
|
||||
maximum: 2
|
||||
solar:
|
||||
type: integer
|
||||
description: The latest solar feed value received
|
||||
grid_ie:
|
||||
type: integer
|
||||
description: The latest grid +I/-E feed value received
|
||||
charge_rate:
|
||||
type: integer
|
||||
description: The divert charge rate
|
||||
available_current:
|
||||
type: integer
|
||||
description: The computed avalible current for divert
|
||||
smoothed_available_current:
|
||||
type: integer
|
||||
description: The computed smoothed available current for divert
|
||||
divert_update:
|
||||
type: number
|
||||
description: The time since the last update of the divert feed
|
||||
divert_active:
|
||||
type: boolean
|
||||
description: "`true` if divert is active, `false` if not"
|
||||
ota_update:
|
||||
type: integer
|
||||
description: "`1`, if there is an OTA update active, `0` if normal operation"
|
||||
time:
|
||||
type: string
|
||||
description: The current time on the WiFi module
|
||||
offset:
|
||||
type: string
|
||||
description: The current timezone
|
||||
6
charger/openevse/types.go
Normal file
6
charger/openevse/types.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package openevse
|
||||
|
||||
type RAPIResponse struct {
|
||||
Cmd string `json:"cmd"`
|
||||
Ret string `json:"ret"`
|
||||
}
|
||||
35
charger/openevse_decorators.go
Normal file
35
charger/openevse_decorators.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenEVSE(base *OpenEVSE, phaseSwitcher func(phases int) error) api.Charger {
|
||||
switch {
|
||||
case phaseSwitcher == nil:
|
||||
return base
|
||||
|
||||
case phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*OpenEVSE
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
OpenEVSE: base,
|
||||
PhaseSwitcher: &decorateOpenEVSEPhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type decorateOpenEVSEPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenEVSEPhaseSwitcherImpl) Phases1p3p(phases int) error {
|
||||
return impl.phaseSwitcher(phases)
|
||||
}
|
||||
2
go.mod
2
go.mod
|
|
@ -18,6 +18,7 @@ require (
|
|||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/containrrr/shoutrrr v0.6.1
|
||||
github.com/coreos/go-oidc/v3 v3.3.0
|
||||
github.com/deepmap/oapi-codegen v1.11.0
|
||||
github.com/denisbrodbeck/machineid v1.0.1
|
||||
github.com/dmarkham/enumer v1.5.6
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
|
|
@ -100,7 +101,6 @@ require (
|
|||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.11.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -244,7 +244,9 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
|
|||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/getkin/kin-openapi v0.94.0 h1:bAxg2vxgnHHHoeefVdmGbR+oxtJlcv5HsJJa3qmAHuo=
|
||||
github.com/getkin/kin-openapi v0.94.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
|
|
@ -267,8 +269,10 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
|
||||
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
|
|
@ -500,6 +504,7 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC
|
|||
github.com/joeshaw/carwings v0.0.0-20220711204617-d90801cf2848 h1:mUoi+B77PKkv/pYCR7uOh5ouZdgzFAwOZ3HU8Jr1P+4=
|
||||
github.com/joeshaw/carwings v0.0.0-20220711204617-d90801cf2848/go.mod h1:tB0OlpicmRVTL1Vksc5XRiYo+wkK2kl/GI7eGMIl6Rs=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpfielding/go-http-digest v0.0.0-20211006141426-fbc93758452e h1:iLmt7czLE9ophoU4xZcckVNCXp+auTvVSQ9MGTWbgBY=
|
||||
github.com/jpfielding/go-http-digest v0.0.0-20211006141426-fbc93758452e/go.mod h1:oLt6zF2euTyCg2Cxz01B3VC5SJcPpKpYnOAqvO+480s=
|
||||
|
|
@ -545,7 +550,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
|
||||
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
|
|
@ -575,6 +582,7 @@ github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
|
|||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
|
||||
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||
|
|
@ -857,7 +865,9 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0
|
|||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
|
||||
|
|
|
|||
20
templates/definition/charger/openevse.yaml
Normal file
20
templates/definition/charger/openevse.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
template: openevse
|
||||
products:
|
||||
- brand: OpenEVSE
|
||||
requirements:
|
||||
description:
|
||||
en: Requires firmware 7.0 or later.
|
||||
de: Benötigt mindestens Firmware 7.0 oder neuer.
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
- name: user
|
||||
required: false
|
||||
- name: password
|
||||
required: false
|
||||
mask: true
|
||||
render: |
|
||||
type: openevse
|
||||
uri: http://{{ .host }}
|
||||
user: {{ .user }}
|
||||
password: {{ .password }}
|
||||
11
templates/docs/charger/openevse_0.yaml
Normal file
11
templates/docs/charger/openevse_0.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
product:
|
||||
brand: OpenEVSE
|
||||
description: |
|
||||
Benötigt mindestens Firmware 7.0 oder neuer.
|
||||
render:
|
||||
- default: |
|
||||
type: template
|
||||
template: openevse
|
||||
host: 192.0.2.2 # IP-Adresse oder Hostname
|
||||
user: # Benutzerkonto (bspw. E-Mail Adresse, User Id, etc.) # Optional
|
||||
password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
"KSE",
|
||||
"Mennekes",
|
||||
"NRGKick",
|
||||
"OpenEVSE",
|
||||
"openWB",
|
||||
"Optec",
|
||||
"PC Electric",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue