diff --git a/charger/openevse.go b/charger/openevse.go new file mode 100644 index 000000000..b9d7d759d --- /dev/null +++ b/charger/openevse.go @@ -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)) +} diff --git a/charger/openevse/api.go b/charger/openevse/api.go new file mode 100644 index 000000000..f8b2aaf55 --- /dev/null +++ b/charger/openevse/api.go @@ -0,0 +1,3490 @@ +// Package openevse provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/deepmap/oapi-codegen version v1.11.0 DO NOT EDIT. +package openevse + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" + "time" + + "github.com/deepmap/oapi-codegen/pkg/runtime" +) + +// Defines values for LogEventType. +const ( + Information LogEventType = "information" + Notification LogEventType = "notification" + Warning LogEventType = "warning" +) + +// Defines values for ScheduleEventDays. +const ( + Friday ScheduleEventDays = "friday" + Monday ScheduleEventDays = "monday" + Saturday ScheduleEventDays = "saturday" + Sunday ScheduleEventDays = "sunday" + Thursday ScheduleEventDays = "thursday" + Tuesday ScheduleEventDays = "tuesday" + Wednesday ScheduleEventDays = "wednesday" +) + +// LogEvent defines model for LogEvent. +type LogEvent struct { + DivertMode *int32 `json:"divertMode,omitempty"` + Elapsed *int32 `json:"elapsed,omitempty"` + Energy *float64 `json:"energy,omitempty"` + EvseFlags *int32 `json:"evseFlags,omitempty"` + EvseState *int `json:"evseState,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + ManagerState *string `json:"managerState,omitempty"` + Pilot *int32 `json:"pilot,omitempty"` + Temperature *float64 `json:"temperature,omitempty"` + TempuratureMax *float64 `json:"tempuratureMax,omitempty"` + Time *time.Time `json:"time,omitempty"` + Type *LogEventType `json:"type,omitempty"` +} + +// LogEventType defines model for LogEvent.Type. +type LogEventType string + +// Message defines model for Message. +type Message struct { + // The message + Msg *string `json:"msg,omitempty"` +} + +// ScheduleEvent defines model for ScheduleEvent. +type ScheduleEvent struct { + Days []ScheduleEventDays `json:"days"` + Id *int `json:"id,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State string `json:"state"` + Time string `json:"time"` +} + +// ScheduleEventDays defines model for ScheduleEvent.Days. +type ScheduleEventDays string + +// BadRequest defines model for BadRequest. +type BadRequest = Message + +// NotFound defines model for NotFound. +type NotFound = Message + +// UpdateSuccessful defines model for UpdateSuccessful. +type UpdateSuccessful = Message + +// SetClaimJSONBody defines parameters for SetClaim. +type SetClaimJSONBody struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` +} + +// UpdateConfigJSONBody defines parameters for UpdateConfig. +type UpdateConfigJSONBody struct { + Buildenv *string `json:"buildenv,omitempty"` + ChargeMode *string `json:"charge_mode,omitempty"` + DiodeCheck *bool `json:"diode_check,omitempty"` + DivertPVRatio *float32 `json:"divert_PV_ratio,omitempty"` + DivertAttackSmoothingFactor *float32 `json:"divert_attack_smoothing_factor,omitempty"` + DivertDecaySmoothingFactor *float32 `json:"divert_decay_smoothing_factor,omitempty"` + DivertEnabled *bool `json:"divert_enabled,omitempty"` + DivertMinChargeTime *float32 `json:"divert_min_charge_time,omitempty"` + EmoncmsApikey *string `json:"emoncms_apikey,omitempty"` + EmoncmsEnabled *bool `json:"emoncms_enabled,omitempty"` + EmoncmsFingerprint *string `json:"emoncms_fingerprint,omitempty"` + EmoncmsNode *string `json:"emoncms_node,omitempty"` + EmoncmsServer *string `json:"emoncms_server,omitempty"` + Espflash *float32 `json:"espflash,omitempty"` + Espinfo *string `json:"espinfo,omitempty"` + Firmware *string `json:"firmware,omitempty"` + Flags *float32 `json:"flags,omitempty"` + GfciCheck *bool `json:"gfci_check,omitempty"` + GroundCheck *bool `json:"ground_check,omitempty"` + Hostname *string `json:"hostname,omitempty"` + HttpSupportedProtocols *[]string `json:"http_supported_protocols,omitempty"` + LedBrightness *float32 `json:"led_brightness,omitempty"` + MaxCurrentHard *int `json:"max_current_hard,omitempty"` + MaxCurrentSoft *int `json:"max_current_soft,omitempty"` + MinCurrentHard *int `json:"min_current_hard,omitempty"` + MqttAnnounceTopic *string `json:"mqtt_announce_topic,omitempty"` + MqttEnabled *bool `json:"mqtt_enabled,omitempty"` + MqttGridIe *string `json:"mqtt_grid_ie,omitempty"` + MqttPass *string `json:"mqtt_pass,omitempty"` + MqttPort *int `json:"mqtt_port,omitempty"` + MqttProtocol *string `json:"mqtt_protocol,omitempty"` + MqttRejectUnauthorized *bool `json:"mqtt_reject_unauthorized,omitempty"` + MqttServer *string `json:"mqtt_server,omitempty"` + MqttSolar *string `json:"mqtt_solar,omitempty"` + MqttSupportedProtocols *[]string `json:"mqtt_supported_protocols,omitempty"` + MqttTopic *string `json:"mqtt_topic,omitempty"` + MqttUser *string `json:"mqtt_user,omitempty"` + MqttVehicleEta *string `json:"mqtt_vehicle_eta,omitempty"` + MqttVehicleRange *string `json:"mqtt_vehicle_range,omitempty"` + MqttVehicleRangeMiles *bool `json:"mqtt_vehicle_range_miles,omitempty"` + MqttVehicleSoc *string `json:"mqtt_vehicle_soc,omitempty"` + MqttVrms *string `json:"mqtt_vrms,omitempty"` + OcppChargeBoxId *string `json:"ocpp_chargeBoxId,omitempty"` + OcppEnabled *bool `json:"ocpp_enabled,omitempty"` + OcppEnergizePlug *bool `json:"ocpp_energize_plug,omitempty"` + OcppIdTag *string `json:"ocpp_idTag,omitempty"` + OcppServer *string `json:"ocpp_server,omitempty"` + OcppSuspendEvse *bool `json:"ocpp_suspend_evse,omitempty"` + Offset *int `json:"offset,omitempty"` + Ohm *string `json:"ohm,omitempty"` + OhmEnabled *bool `json:"ohm_enabled,omitempty"` + Pass *string `json:"pass,omitempty"` + PauseUsesDisabled *bool `json:"pause_uses_disabled,omitempty"` + Protocol *string `json:"protocol,omitempty"` + RelayCheck *bool `json:"relay_check,omitempty"` + Scale *int `json:"scale,omitempty"` + Service *int `json:"service,omitempty"` + SntpEnabled *bool `json:"sntp_enabled,omitempty"` + SntpHostname *string `json:"sntp_hostname,omitempty"` + Ssid *string `json:"ssid,omitempty"` + TempCheck *bool `json:"temp_check,omitempty"` + TeslaAccessToken *string `json:"tesla_access_token,omitempty"` + TeslaCreatedAt *float32 `json:"tesla_created_at,omitempty"` + TeslaEnabled *bool `json:"tesla_enabled,omitempty"` + TeslaExpiresIn *float32 `json:"tesla_expires_in,omitempty"` + TeslaRefreshToken *string `json:"tesla_refresh_token,omitempty"` + TeslaVehicleId *string `json:"tesla_vehicle_id,omitempty"` + TimeZone *string `json:"time_zone,omitempty"` + TxStartPoint *string `json:"tx_start_point,omitempty"` + VentCheck *bool `json:"vent_check,omitempty"` + Version *string `json:"version,omitempty"` + WwwPassword *string `json:"www_password,omitempty"` + WwwUsername *string `json:"www_username,omitempty"` +} + +// SetManualOverrideJSONBody defines parameters for SetManualOverride. +type SetManualOverrideJSONBody struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` +} + +// UpdateScheduleJSONBody defines parameters for UpdateSchedule. +type UpdateScheduleJSONBody = []ScheduleEvent + +// SetScheduleEventJSONBody defines parameters for SetScheduleEvent. +type SetScheduleEventJSONBody = string + +// SetClaimJSONRequestBody defines body for SetClaim for application/json ContentType. +type SetClaimJSONRequestBody SetClaimJSONBody + +// UpdateConfigJSONRequestBody defines body for UpdateConfig for application/json ContentType. +type UpdateConfigJSONRequestBody UpdateConfigJSONBody + +// SetManualOverrideJSONRequestBody defines body for SetManualOverride for application/json ContentType. +type SetManualOverrideJSONRequestBody SetManualOverrideJSONBody + +// UpdateScheduleJSONRequestBody defines body for UpdateSchedule for application/json ContentType. +type UpdateScheduleJSONRequestBody = UpdateScheduleJSONBody + +// SetScheduleEventJSONRequestBody defines body for SetScheduleEvent for application/json ContentType. +type SetScheduleEventJSONRequestBody = SetScheduleEventJSONBody + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// Doer performs HTTP requests. +// +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// Client which conforms to the OpenAPI3 specification for this service. +type Client struct { + // The endpoint of the server conforming to this interface, with scheme, + // https://api.deepmap.com for example. This can contain a path relative + // to the server, such as https://api.deepmap.com/dev-test, and all the + // paths in the swagger spec will be appended to the server. + Server string + + // Doer for performing requests, typically a *http.Client with any + // customized settings, such as certificate chains. + Client HttpRequestDoer + + // A list of callbacks for modifying requests which are generated before sending over + // the network. + RequestEditors []RequestEditorFn +} + +// ClientOption allows setting custom parameters during construction +type ClientOption func(*Client) error + +// Creates a new Client, with reasonable defaults +func NewClient(server string, opts ...ClientOption) (*Client, error) { + // create a client with sane default values + client := Client{ + Server: server, + } + // mutate client and add all optional params + for _, o := range opts { + if err := o(&client); err != nil { + return nil, err + } + } + // ensure the server URL always has a trailing slash + if !strings.HasSuffix(client.Server, "/") { + client.Server += "/" + } + // create httpClient, if not already present + if client.Client == nil { + client.Client = &http.Client{} + } + return &client, nil +} + +// WithHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithHTTPClient(doer HttpRequestDoer) ClientOption { + return func(c *Client) error { + c.Client = doer + return nil + } +} + +// WithRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithRequestEditorFn(fn RequestEditorFn) ClientOption { + return func(c *Client) error { + c.RequestEditors = append(c.RequestEditors, fn) + return nil + } +} + +// The interface specification for the client above. +type ClientInterface interface { + // ListClaims request + ListClaims(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ReleaseClaim request + ReleaseClaim(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetClaim request + GetClaim(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*http.Response, error) + + // SetClaim request with any body + SetClaimWithBody(ctx context.Context, client int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + SetClaim(ctx context.Context, client int, body SetClaimJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetConfig request + GetConfig(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateConfig request with any body + UpdateConfigWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateConfig(ctx context.Context, body UpdateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetEventBlockInfo request + GetEventBlockInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetEventBlock request + GetEventBlock(ctx context.Context, index int, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ClearManualOverride request + ClearManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetManualOverride request + GetManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ToggleManualOverride request + ToggleManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // SetManualOverride request with any body + SetManualOverrideWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + SetManualOverride(ctx context.Context, body SetManualOverrideJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ListSchedule request + ListSchedule(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateSchedule request with any body + UpdateScheduleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateSchedule(ctx context.Context, body UpdateScheduleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // RemoveScheduleEvent request + RemoveScheduleEvent(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetScheduleEvent request + GetScheduleEvent(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*http.Response, error) + + // SetScheduleEvent request with any body + SetScheduleEventWithBody(ctx context.Context, id int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + SetScheduleEvent(ctx context.Context, id int, body SetScheduleEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetStatus request + GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetTeslaVehicles request + GetTeslaVehicles(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // StatusUpdates request + StatusUpdates(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) ListClaims(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListClaimsRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ReleaseClaim(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReleaseClaimRequest(c.Server, client) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetClaim(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetClaimRequest(c.Server, client) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetClaimWithBody(ctx context.Context, client int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetClaimRequestWithBody(c.Server, client, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetClaim(ctx context.Context, client int, body SetClaimJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetClaimRequest(c.Server, client, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetConfig(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetConfigRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateConfigWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateConfigRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateConfig(ctx context.Context, body UpdateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateConfigRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetEventBlockInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetEventBlockInfoRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetEventBlock(ctx context.Context, index int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetEventBlockRequest(c.Server, index) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ClearManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewClearManualOverrideRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetManualOverrideRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ToggleManualOverride(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewToggleManualOverrideRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetManualOverrideWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetManualOverrideRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetManualOverride(ctx context.Context, body SetManualOverrideJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetManualOverrideRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) ListSchedule(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListScheduleRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateScheduleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateScheduleRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateSchedule(ctx context.Context, body UpdateScheduleJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateScheduleRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) RemoveScheduleEvent(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewRemoveScheduleEventRequest(c.Server, id) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetScheduleEvent(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetScheduleEventRequest(c.Server, id) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetScheduleEventWithBody(ctx context.Context, id int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetScheduleEventRequestWithBody(c.Server, id, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetScheduleEvent(ctx context.Context, id int, body SetScheduleEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetScheduleEventRequest(c.Server, id, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetStatusRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetTeslaVehicles(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetTeslaVehiclesRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) StatusUpdates(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewStatusUpdatesRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewListClaimsRequest generates requests for ListClaims +func NewListClaimsRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/claims") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewReleaseClaimRequest generates requests for ReleaseClaim +func NewReleaseClaimRequest(server string, client int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "client", runtime.ParamLocationPath, client) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/claims/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetClaimRequest generates requests for GetClaim +func NewGetClaimRequest(server string, client int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "client", runtime.ParamLocationPath, client) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/claims/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewSetClaimRequest calls the generic SetClaim builder with application/json body +func NewSetClaimRequest(server string, client int, body SetClaimJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewSetClaimRequestWithBody(server, client, "application/json", bodyReader) +} + +// NewSetClaimRequestWithBody generates requests for SetClaim with any type of body +func NewSetClaimRequestWithBody(server string, client int, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "client", runtime.ParamLocationPath, client) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/claims/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetConfigRequest generates requests for GetConfig +func NewGetConfigRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/config") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewUpdateConfigRequest calls the generic UpdateConfig builder with application/json body +func NewUpdateConfigRequest(server string, body UpdateConfigJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateConfigRequestWithBody(server, "application/json", bodyReader) +} + +// NewUpdateConfigRequestWithBody generates requests for UpdateConfig with any type of body +func NewUpdateConfigRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/config") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetEventBlockInfoRequest generates requests for GetEventBlockInfo +func NewGetEventBlockInfoRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/logs") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetEventBlockRequest generates requests for GetEventBlock +func NewGetEventBlockRequest(server string, index int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "index", runtime.ParamLocationPath, index) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/logs/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewClearManualOverrideRequest generates requests for ClearManualOverride +func NewClearManualOverrideRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/override") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetManualOverrideRequest generates requests for GetManualOverride +func NewGetManualOverrideRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/override") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewToggleManualOverrideRequest generates requests for ToggleManualOverride +func NewToggleManualOverrideRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/override") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PATCH", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewSetManualOverrideRequest calls the generic SetManualOverride builder with application/json body +func NewSetManualOverrideRequest(server string, body SetManualOverrideJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewSetManualOverrideRequestWithBody(server, "application/json", bodyReader) +} + +// NewSetManualOverrideRequestWithBody generates requests for SetManualOverride with any type of body +func NewSetManualOverrideRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/override") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewListScheduleRequest generates requests for ListSchedule +func NewListScheduleRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/schedule") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewUpdateScheduleRequest calls the generic UpdateSchedule builder with application/json body +func NewUpdateScheduleRequest(server string, body UpdateScheduleJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateScheduleRequestWithBody(server, "application/json", bodyReader) +} + +// NewUpdateScheduleRequestWithBody generates requests for UpdateSchedule with any type of body +func NewUpdateScheduleRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/schedule") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewRemoveScheduleEventRequest generates requests for RemoveScheduleEvent +func NewRemoveScheduleEventRequest(server string, id int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/schedule/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetScheduleEventRequest generates requests for GetScheduleEvent +func NewGetScheduleEventRequest(server string, id int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/schedule/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewSetScheduleEventRequest calls the generic SetScheduleEvent builder with application/json body +func NewSetScheduleEventRequest(server string, id int, body SetScheduleEventJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewSetScheduleEventRequestWithBody(server, id, "application/json", bodyReader) +} + +// NewSetScheduleEventRequestWithBody generates requests for SetScheduleEvent with any type of body +func NewSetScheduleEventRequestWithBody(server string, id int, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/schedule/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetStatusRequest generates requests for GetStatus +func NewGetStatusRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/status") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetTeslaVehiclesRequest generates requests for GetTeslaVehicles +func NewGetTeslaVehiclesRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/tesla/vehicles") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewStatusUpdatesRequest generates requests for StatusUpdates +func NewStatusUpdatesRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/ws") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range c.RequestEditors { + if err := r(ctx, req); err != nil { + return err + } + } + for _, r := range additionalEditors { + if err := r(ctx, req); err != nil { + return err + } + } + return nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses creates a new ClientWithResponses, which wraps +// Client with return type handling +func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &ClientWithResponses{client}, nil +} + +// WithBaseURL overrides the baseURL. +func WithBaseURL(baseURL string) ClientOption { + return func(c *Client) error { + newBaseURL, err := url.Parse(baseURL) + if err != nil { + return err + } + c.Server = newBaseURL.String() + return nil + } +} + +// ClientWithResponsesInterface is the interface specification for the client with responses above. +type ClientWithResponsesInterface interface { + // ListClaims request + ListClaimsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListClaimsResponse, error) + + // ReleaseClaim request + ReleaseClaimWithResponse(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*ReleaseClaimResponse, error) + + // GetClaim request + GetClaimWithResponse(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*GetClaimResponse, error) + + // SetClaim request with any body + SetClaimWithBodyWithResponse(ctx context.Context, client int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetClaimResponse, error) + + SetClaimWithResponse(ctx context.Context, client int, body SetClaimJSONRequestBody, reqEditors ...RequestEditorFn) (*SetClaimResponse, error) + + // GetConfig request + GetConfigWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetConfigResponse, error) + + // UpdateConfig request with any body + UpdateConfigWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateConfigResponse, error) + + UpdateConfigWithResponse(ctx context.Context, body UpdateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateConfigResponse, error) + + // GetEventBlockInfo request + GetEventBlockInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEventBlockInfoResponse, error) + + // GetEventBlock request + GetEventBlockWithResponse(ctx context.Context, index int, reqEditors ...RequestEditorFn) (*GetEventBlockResponse, error) + + // ClearManualOverride request + ClearManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ClearManualOverrideResponse, error) + + // GetManualOverride request + GetManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetManualOverrideResponse, error) + + // ToggleManualOverride request + ToggleManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ToggleManualOverrideResponse, error) + + // SetManualOverride request with any body + SetManualOverrideWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetManualOverrideResponse, error) + + SetManualOverrideWithResponse(ctx context.Context, body SetManualOverrideJSONRequestBody, reqEditors ...RequestEditorFn) (*SetManualOverrideResponse, error) + + // ListSchedule request + ListScheduleWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListScheduleResponse, error) + + // UpdateSchedule request with any body + UpdateScheduleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateScheduleResponse, error) + + UpdateScheduleWithResponse(ctx context.Context, body UpdateScheduleJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateScheduleResponse, error) + + // RemoveScheduleEvent request + RemoveScheduleEventWithResponse(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*RemoveScheduleEventResponse, error) + + // GetScheduleEvent request + GetScheduleEventWithResponse(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*GetScheduleEventResponse, error) + + // SetScheduleEvent request with any body + SetScheduleEventWithBodyWithResponse(ctx context.Context, id int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetScheduleEventResponse, error) + + SetScheduleEventWithResponse(ctx context.Context, id int, body SetScheduleEventJSONRequestBody, reqEditors ...RequestEditorFn) (*SetScheduleEventResponse, error) + + // GetStatus request + GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse, error) + + // GetTeslaVehicles request + GetTeslaVehiclesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTeslaVehiclesResponse, error) + + // StatusUpdates request + StatusUpdatesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*StatusUpdatesResponse, error) +} + +type ListClaimsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // The client ID, defined by [OpenEVSE](src/evse_man.h#L25) + Client *int `json:"client,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // The priority of the claim, the higher the number the higher the priority + Priority *int `json:"priority,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r ListClaimsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListClaimsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ReleaseClaimResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message + JSON404 *Message +} + +// Status returns HTTPResponse.Status +func (r ReleaseClaimResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReleaseClaimResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetClaimResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } + JSON404 *Message +} + +// Status returns HTTPResponse.Status +func (r GetClaimResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetClaimResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type SetClaimResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message + JSON400 *Message +} + +// Status returns HTTPResponse.Status +func (r SetClaimResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r SetClaimResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetConfigResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Buildenv *string `json:"buildenv,omitempty"` + ChargeMode *string `json:"charge_mode,omitempty"` + DiodeCheck *bool `json:"diode_check,omitempty"` + DivertPVRatio *float32 `json:"divert_PV_ratio,omitempty"` + DivertAttackSmoothingFactor *float32 `json:"divert_attack_smoothing_factor,omitempty"` + DivertDecaySmoothingFactor *float32 `json:"divert_decay_smoothing_factor,omitempty"` + DivertEnabled *bool `json:"divert_enabled,omitempty"` + DivertMinChargeTime *float32 `json:"divert_min_charge_time,omitempty"` + EmoncmsApikey *string `json:"emoncms_apikey,omitempty"` + EmoncmsEnabled *bool `json:"emoncms_enabled,omitempty"` + EmoncmsFingerprint *string `json:"emoncms_fingerprint,omitempty"` + EmoncmsNode *string `json:"emoncms_node,omitempty"` + EmoncmsServer *string `json:"emoncms_server,omitempty"` + Espflash *float32 `json:"espflash,omitempty"` + Espinfo *string `json:"espinfo,omitempty"` + Firmware *string `json:"firmware,omitempty"` + Flags *float32 `json:"flags,omitempty"` + GfciCheck *bool `json:"gfci_check,omitempty"` + GroundCheck *bool `json:"ground_check,omitempty"` + Hostname *string `json:"hostname,omitempty"` + HttpSupportedProtocols *[]string `json:"http_supported_protocols,omitempty"` + LedBrightness *float32 `json:"led_brightness,omitempty"` + MaxCurrentHard *int `json:"max_current_hard,omitempty"` + MaxCurrentSoft *int `json:"max_current_soft,omitempty"` + MinCurrentHard *int `json:"min_current_hard,omitempty"` + MqttAnnounceTopic *string `json:"mqtt_announce_topic,omitempty"` + MqttEnabled *bool `json:"mqtt_enabled,omitempty"` + MqttGridIe *string `json:"mqtt_grid_ie,omitempty"` + MqttPass *string `json:"mqtt_pass,omitempty"` + MqttPort *int `json:"mqtt_port,omitempty"` + MqttProtocol *string `json:"mqtt_protocol,omitempty"` + MqttRejectUnauthorized *bool `json:"mqtt_reject_unauthorized,omitempty"` + MqttServer *string `json:"mqtt_server,omitempty"` + MqttSolar *string `json:"mqtt_solar,omitempty"` + MqttSupportedProtocols *[]string `json:"mqtt_supported_protocols,omitempty"` + MqttTopic *string `json:"mqtt_topic,omitempty"` + MqttUser *string `json:"mqtt_user,omitempty"` + MqttVehicleEta *string `json:"mqtt_vehicle_eta,omitempty"` + MqttVehicleRange *string `json:"mqtt_vehicle_range,omitempty"` + MqttVehicleRangeMiles *bool `json:"mqtt_vehicle_range_miles,omitempty"` + MqttVehicleSoc *string `json:"mqtt_vehicle_soc,omitempty"` + MqttVrms *string `json:"mqtt_vrms,omitempty"` + OcppChargeBoxId *string `json:"ocpp_chargeBoxId,omitempty"` + OcppEnabled *bool `json:"ocpp_enabled,omitempty"` + OcppEnergizePlug *bool `json:"ocpp_energize_plug,omitempty"` + OcppIdTag *string `json:"ocpp_idTag,omitempty"` + OcppServer *string `json:"ocpp_server,omitempty"` + OcppSuspendEvse *bool `json:"ocpp_suspend_evse,omitempty"` + Offset *int `json:"offset,omitempty"` + Ohm *string `json:"ohm,omitempty"` + OhmEnabled *bool `json:"ohm_enabled,omitempty"` + Pass *string `json:"pass,omitempty"` + PauseUsesDisabled *bool `json:"pause_uses_disabled,omitempty"` + Protocol *string `json:"protocol,omitempty"` + RelayCheck *bool `json:"relay_check,omitempty"` + Scale *int `json:"scale,omitempty"` + Service *int `json:"service,omitempty"` + SntpEnabled *bool `json:"sntp_enabled,omitempty"` + SntpHostname *string `json:"sntp_hostname,omitempty"` + Ssid *string `json:"ssid,omitempty"` + TempCheck *bool `json:"temp_check,omitempty"` + TeslaAccessToken *string `json:"tesla_access_token,omitempty"` + TeslaCreatedAt *float32 `json:"tesla_created_at,omitempty"` + TeslaEnabled *bool `json:"tesla_enabled,omitempty"` + TeslaExpiresIn *float32 `json:"tesla_expires_in,omitempty"` + TeslaRefreshToken *string `json:"tesla_refresh_token,omitempty"` + TeslaVehicleId *string `json:"tesla_vehicle_id,omitempty"` + TimeZone *string `json:"time_zone,omitempty"` + TxStartPoint *string `json:"tx_start_point,omitempty"` + VentCheck *bool `json:"vent_check,omitempty"` + Version *string `json:"version,omitempty"` + WwwPassword *string `json:"www_password,omitempty"` + WwwUsername *string `json:"www_username,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetConfigResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetConfigResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateConfigResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message + JSON400 *Message +} + +// Status returns HTTPResponse.Status +func (r UpdateConfigResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateConfigResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetEventBlockInfoResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Max *int `json:"max,omitempty"` + Min *int `json:"min,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetEventBlockInfoResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetEventBlockInfoResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetEventBlockResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]LogEvent + JSON404 *Message +} + +// Status returns HTTPResponse.Status +func (r GetEventBlockResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetEventBlockResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ClearManualOverrideResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r ClearManualOverrideResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ClearManualOverrideResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetManualOverrideResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } + JSON404 *Message +} + +// Status returns HTTPResponse.Status +func (r GetManualOverrideResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetManualOverrideResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ToggleManualOverrideResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r ToggleManualOverrideResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ToggleManualOverrideResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type SetManualOverrideResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message +} + +// Status returns HTTPResponse.Status +func (r SetManualOverrideResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r SetManualOverrideResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ListScheduleResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]ScheduleEvent + JSON400 *Message +} + +// Status returns HTTPResponse.Status +func (r ListScheduleResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListScheduleResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateScheduleResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r UpdateScheduleResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateScheduleResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type RemoveScheduleEventResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message +} + +// Status returns HTTPResponse.Status +func (r RemoveScheduleEventResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r RemoveScheduleEventResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetScheduleEventResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *string +} + +// Status returns HTTPResponse.Status +func (r GetScheduleEventResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetScheduleEventResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type SetScheduleEventResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Message +} + +// Status returns HTTPResponse.Status +func (r SetScheduleEventResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r SetScheduleEventResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetStatusResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + // the value of the charge current in mA + Amp *float32 `json:"amp,omitempty"` + + // The computed avalible current for divert + AvailableCurrent *int `json:"available_current,omitempty"` + + // The divert charge rate + ChargeRate *int `json:"charge_rate,omitempty"` + + // The LCD colour + Colour *int `json:"colour,omitempty"` + + // Number of RAPI messages sent + CommSent *int `json:"comm_sent,omitempty"` + + // Number of successful RAPI messages + CommSuccess *int `json:"comm_success,omitempty"` + + // `true` if divert is active, `false` if not + DivertActive *bool `json:"divert_active,omitempty"` + + // The time since the last update of the divert feed + DivertUpdate *float32 `json:"divert_update,omitempty"` + + // The PV divert mode, `1` normal, `2` Eco + Divertmode *int `json:"divertmode,omitempty"` + + // The duration of the current charge session, in seconds + Elapsed *float32 `json:"elapsed,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + EmoncmsConnected *int `json:"emoncms_connected,omitempty"` + + // Last response message from the EmonCMS server + EmoncmsMessage *string `json:"emoncms_message,omitempty"` + + // `1`, Wired ethernet is connected, `0` no wired ethernet connection + EthConnected *int `json:"eth_connected,omitempty"` + + // `1`, if the WiFi module has negociated a connection to the OpenEVSE module, `0` not connected + EvseConnected *int `json:"evse_connected,omitempty"` + + // Number of bytes free in the ESP memory heap + FreeHeap *int `json:"free_heap,omitempty"` + + // Number of GFCI errors + Gfcicount *int `json:"gfcicount,omitempty"` + + // The latest grid +I/-E feed value received + GridIe *int `json:"grid_ie,omitempty"` + + // The current IP address of the WiFi module + Ipaddress *string `json:"ipaddress,omitempty"` + + // `1`, if the manual override is active, `0` default behaviour + ManualOverride *int `json:"manual_override,omitempty"` + + // The current mode of the EVSE + Mode *string `json:"mode,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + MqttConnected *int `json:"mqtt_connected,omitempty"` + + // `1`, network is connected, either wired or WiFi, `0` no network connection + NetConnected *int `json:"net_connected,omitempty"` + + // Number of no ground errors + Nogndcount *int `json:"nogndcount,omitempty"` + + // The current timezone + Offset *string `json:"offset,omitempty"` + + // Last status message from the OhmHour connection + OhmHour *string `json:"ohm_hour,omitempty"` + + // `1`, if there is an OTA update active, `0` if normal operation + OtaUpdate *int `json:"ota_update,omitempty"` + + // The number of posts sent to the EmonCMS server + PacketsSent *int `json:"packets_sent,omitempty"` + + // The number of successful posts to the EmonCMS server + PacketsSuccess *int `json:"packets_success,omitempty"` + + // the pilot value, in amps + Pilot *int `json:"pilot,omitempty"` + + // `1`, if RAPI messages have successfully been sent to the OpenEVSE module, `0` not connected + RapiConnected *int `json:"rapi_connected,omitempty"` + + // The current service level + ServiceLevel *int `json:"service_level,omitempty"` + + // The computed smoothed available current for divert + SmoothedAvailableCurrent *int `json:"smoothed_available_current,omitempty"` + + // The latest solar feed value received + Solar *int `json:"solar,omitempty"` + + // WiFi RSSI signal strength + Srssi *int `json:"srssi,omitempty"` + + // The EVSE status + State *int `json:"state,omitempty"` + + // Number of stuck relay errors + Stuckcount *int `json:"stuckcount,omitempty"` + + // the derived temperature, in 1/10th °C + Temp *float32 `json:"temp,omitempty"` + + // The current time on the WiFi module + Time *string `json:"time,omitempty"` + + // `1`, if a vehicle id connected to the EVSE, `0` not connected + Vehicle *int `json:"vehicle,omitempty"` + + // the charge voltage, read form the EVSE if supported, or supplied via MQTT or other external source + Voltage *float32 `json:"voltage,omitempty"` + + // The total amount of energy transfered, in W/hour + Watthour *int `json:"watthour,omitempty"` + + // The amount of energy transfered in this charge session, in W/sec + Wattsec *float32 `json:"wattsec,omitempty"` + + // `1`, WiFi is connected, `0` no WiFi connection + WifiClientConnected *int `json:"wifi_client_connected,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetStatusResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetStatusResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetTeslaVehiclesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Count float32 `json:"count"` + Vehicles []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"vehicles"` + } +} + +// Status returns HTTPResponse.Status +func (r GetTeslaVehiclesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetTeslaVehiclesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type StatusUpdatesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + // the value of the charge current in mA + Amp *float32 `json:"amp,omitempty"` + + // The computed avalible current for divert + AvailableCurrent *int `json:"available_current,omitempty"` + + // The divert charge rate + ChargeRate *int `json:"charge_rate,omitempty"` + + // The LCD colour + Colour *int `json:"colour,omitempty"` + + // Number of RAPI messages sent + CommSent *int `json:"comm_sent,omitempty"` + + // Number of successful RAPI messages + CommSuccess *int `json:"comm_success,omitempty"` + + // `true` if divert is active, `false` if not + DivertActive *bool `json:"divert_active,omitempty"` + + // The time since the last update of the divert feed + DivertUpdate *float32 `json:"divert_update,omitempty"` + + // The PV divert mode, `1` normal, `2` Eco + Divertmode *int `json:"divertmode,omitempty"` + + // The duration of the current charge session, in seconds + Elapsed *float32 `json:"elapsed,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + EmoncmsConnected *int `json:"emoncms_connected,omitempty"` + + // Last response message from the EmonCMS server + EmoncmsMessage *string `json:"emoncms_message,omitempty"` + + // `1`, Wired ethernet is connected, `0` no wired ethernet connection + EthConnected *int `json:"eth_connected,omitempty"` + + // `1`, if the WiFi module has negociated a connection to the OpenEVSE module, `0` not connected + EvseConnected *int `json:"evse_connected,omitempty"` + + // Number of bytes free in the ESP memory heap + FreeHeap *int `json:"free_heap,omitempty"` + + // Number of GFCI errors + Gfcicount *int `json:"gfcicount,omitempty"` + + // The latest grid +I/-E feed value received + GridIe *int `json:"grid_ie,omitempty"` + + // The current IP address of the WiFi module + Ipaddress *string `json:"ipaddress,omitempty"` + + // `1`, if the manual override is active, `0` default behaviour + ManualOverride *int `json:"manual_override,omitempty"` + + // The current mode of the EVSE + Mode *string `json:"mode,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + MqttConnected *int `json:"mqtt_connected,omitempty"` + + // `1`, network is connected, either wired or WiFi, `0` no network connection + NetConnected *int `json:"net_connected,omitempty"` + + // Number of no ground errors + Nogndcount *int `json:"nogndcount,omitempty"` + + // The current timezone + Offset *string `json:"offset,omitempty"` + + // Last status message from the OhmHour connection + OhmHour *string `json:"ohm_hour,omitempty"` + + // `1`, if there is an OTA update active, `0` if normal operation + OtaUpdate *int `json:"ota_update,omitempty"` + + // The number of posts sent to the EmonCMS server + PacketsSent *int `json:"packets_sent,omitempty"` + + // The number of successful posts to the EmonCMS server + PacketsSuccess *int `json:"packets_success,omitempty"` + + // the pilot value, in amps + Pilot *int `json:"pilot,omitempty"` + + // `1`, if RAPI messages have successfully been sent to the OpenEVSE module, `0` not connected + RapiConnected *int `json:"rapi_connected,omitempty"` + + // The current service level + ServiceLevel *int `json:"service_level,omitempty"` + + // The computed smoothed available current for divert + SmoothedAvailableCurrent *int `json:"smoothed_available_current,omitempty"` + + // The latest solar feed value received + Solar *int `json:"solar,omitempty"` + + // WiFi RSSI signal strength + Srssi *int `json:"srssi,omitempty"` + + // The EVSE status + State *int `json:"state,omitempty"` + + // Number of stuck relay errors + Stuckcount *int `json:"stuckcount,omitempty"` + + // the derived temperature, in 1/10th °C + Temp *float32 `json:"temp,omitempty"` + + // The current time on the WiFi module + Time *string `json:"time,omitempty"` + + // `1`, if a vehicle id connected to the EVSE, `0` not connected + Vehicle *int `json:"vehicle,omitempty"` + + // the charge voltage, read form the EVSE if supported, or supplied via MQTT or other external source + Voltage *float32 `json:"voltage,omitempty"` + + // The total amount of energy transfered, in W/hour + Watthour *int `json:"watthour,omitempty"` + + // The amount of energy transfered in this charge session, in W/sec + Wattsec *float32 `json:"wattsec,omitempty"` + + // `1`, WiFi is connected, `0` no WiFi connection + WifiClientConnected *int `json:"wifi_client_connected,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r StatusUpdatesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r StatusUpdatesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ListClaimsWithResponse request returning *ListClaimsResponse +func (c *ClientWithResponses) ListClaimsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListClaimsResponse, error) { + rsp, err := c.ListClaims(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseListClaimsResponse(rsp) +} + +// ReleaseClaimWithResponse request returning *ReleaseClaimResponse +func (c *ClientWithResponses) ReleaseClaimWithResponse(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*ReleaseClaimResponse, error) { + rsp, err := c.ReleaseClaim(ctx, client, reqEditors...) + if err != nil { + return nil, err + } + return ParseReleaseClaimResponse(rsp) +} + +// GetClaimWithResponse request returning *GetClaimResponse +func (c *ClientWithResponses) GetClaimWithResponse(ctx context.Context, client int, reqEditors ...RequestEditorFn) (*GetClaimResponse, error) { + rsp, err := c.GetClaim(ctx, client, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetClaimResponse(rsp) +} + +// SetClaimWithBodyWithResponse request with arbitrary body returning *SetClaimResponse +func (c *ClientWithResponses) SetClaimWithBodyWithResponse(ctx context.Context, client int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetClaimResponse, error) { + rsp, err := c.SetClaimWithBody(ctx, client, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetClaimResponse(rsp) +} + +func (c *ClientWithResponses) SetClaimWithResponse(ctx context.Context, client int, body SetClaimJSONRequestBody, reqEditors ...RequestEditorFn) (*SetClaimResponse, error) { + rsp, err := c.SetClaim(ctx, client, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetClaimResponse(rsp) +} + +// GetConfigWithResponse request returning *GetConfigResponse +func (c *ClientWithResponses) GetConfigWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetConfigResponse, error) { + rsp, err := c.GetConfig(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetConfigResponse(rsp) +} + +// UpdateConfigWithBodyWithResponse request with arbitrary body returning *UpdateConfigResponse +func (c *ClientWithResponses) UpdateConfigWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateConfigResponse, error) { + rsp, err := c.UpdateConfigWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateConfigResponse(rsp) +} + +func (c *ClientWithResponses) UpdateConfigWithResponse(ctx context.Context, body UpdateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateConfigResponse, error) { + rsp, err := c.UpdateConfig(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateConfigResponse(rsp) +} + +// GetEventBlockInfoWithResponse request returning *GetEventBlockInfoResponse +func (c *ClientWithResponses) GetEventBlockInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEventBlockInfoResponse, error) { + rsp, err := c.GetEventBlockInfo(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetEventBlockInfoResponse(rsp) +} + +// GetEventBlockWithResponse request returning *GetEventBlockResponse +func (c *ClientWithResponses) GetEventBlockWithResponse(ctx context.Context, index int, reqEditors ...RequestEditorFn) (*GetEventBlockResponse, error) { + rsp, err := c.GetEventBlock(ctx, index, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetEventBlockResponse(rsp) +} + +// ClearManualOverrideWithResponse request returning *ClearManualOverrideResponse +func (c *ClientWithResponses) ClearManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ClearManualOverrideResponse, error) { + rsp, err := c.ClearManualOverride(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseClearManualOverrideResponse(rsp) +} + +// GetManualOverrideWithResponse request returning *GetManualOverrideResponse +func (c *ClientWithResponses) GetManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetManualOverrideResponse, error) { + rsp, err := c.GetManualOverride(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetManualOverrideResponse(rsp) +} + +// ToggleManualOverrideWithResponse request returning *ToggleManualOverrideResponse +func (c *ClientWithResponses) ToggleManualOverrideWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ToggleManualOverrideResponse, error) { + rsp, err := c.ToggleManualOverride(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseToggleManualOverrideResponse(rsp) +} + +// SetManualOverrideWithBodyWithResponse request with arbitrary body returning *SetManualOverrideResponse +func (c *ClientWithResponses) SetManualOverrideWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetManualOverrideResponse, error) { + rsp, err := c.SetManualOverrideWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetManualOverrideResponse(rsp) +} + +func (c *ClientWithResponses) SetManualOverrideWithResponse(ctx context.Context, body SetManualOverrideJSONRequestBody, reqEditors ...RequestEditorFn) (*SetManualOverrideResponse, error) { + rsp, err := c.SetManualOverride(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetManualOverrideResponse(rsp) +} + +// ListScheduleWithResponse request returning *ListScheduleResponse +func (c *ClientWithResponses) ListScheduleWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListScheduleResponse, error) { + rsp, err := c.ListSchedule(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseListScheduleResponse(rsp) +} + +// UpdateScheduleWithBodyWithResponse request with arbitrary body returning *UpdateScheduleResponse +func (c *ClientWithResponses) UpdateScheduleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateScheduleResponse, error) { + rsp, err := c.UpdateScheduleWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateScheduleResponse(rsp) +} + +func (c *ClientWithResponses) UpdateScheduleWithResponse(ctx context.Context, body UpdateScheduleJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateScheduleResponse, error) { + rsp, err := c.UpdateSchedule(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateScheduleResponse(rsp) +} + +// RemoveScheduleEventWithResponse request returning *RemoveScheduleEventResponse +func (c *ClientWithResponses) RemoveScheduleEventWithResponse(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*RemoveScheduleEventResponse, error) { + rsp, err := c.RemoveScheduleEvent(ctx, id, reqEditors...) + if err != nil { + return nil, err + } + return ParseRemoveScheduleEventResponse(rsp) +} + +// GetScheduleEventWithResponse request returning *GetScheduleEventResponse +func (c *ClientWithResponses) GetScheduleEventWithResponse(ctx context.Context, id int, reqEditors ...RequestEditorFn) (*GetScheduleEventResponse, error) { + rsp, err := c.GetScheduleEvent(ctx, id, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetScheduleEventResponse(rsp) +} + +// SetScheduleEventWithBodyWithResponse request with arbitrary body returning *SetScheduleEventResponse +func (c *ClientWithResponses) SetScheduleEventWithBodyWithResponse(ctx context.Context, id int, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetScheduleEventResponse, error) { + rsp, err := c.SetScheduleEventWithBody(ctx, id, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetScheduleEventResponse(rsp) +} + +func (c *ClientWithResponses) SetScheduleEventWithResponse(ctx context.Context, id int, body SetScheduleEventJSONRequestBody, reqEditors ...RequestEditorFn) (*SetScheduleEventResponse, error) { + rsp, err := c.SetScheduleEvent(ctx, id, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetScheduleEventResponse(rsp) +} + +// GetStatusWithResponse request returning *GetStatusResponse +func (c *ClientWithResponses) GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse, error) { + rsp, err := c.GetStatus(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetStatusResponse(rsp) +} + +// GetTeslaVehiclesWithResponse request returning *GetTeslaVehiclesResponse +func (c *ClientWithResponses) GetTeslaVehiclesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTeslaVehiclesResponse, error) { + rsp, err := c.GetTeslaVehicles(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetTeslaVehiclesResponse(rsp) +} + +// StatusUpdatesWithResponse request returning *StatusUpdatesResponse +func (c *ClientWithResponses) StatusUpdatesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*StatusUpdatesResponse, error) { + rsp, err := c.StatusUpdates(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseStatusUpdatesResponse(rsp) +} + +// ParseListClaimsResponse parses an HTTP response from a ListClaimsWithResponse call +func ParseListClaimsResponse(rsp *http.Response) (*ListClaimsResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListClaimsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // The client ID, defined by [OpenEVSE](src/evse_man.h#L25) + Client *int `json:"client,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // The priority of the claim, the higher the number the higher the priority + Priority *int `json:"priority,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseReleaseClaimResponse parses an HTTP response from a ReleaseClaimWithResponse call +func ParseReleaseClaimResponse(rsp *http.Response) (*ReleaseClaimResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReleaseClaimResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseGetClaimResponse parses an HTTP response from a GetClaimWithResponse call +func ParseGetClaimResponse(rsp *http.Response) (*GetClaimResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetClaimResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseSetClaimResponse parses an HTTP response from a SetClaimWithResponse call +func ParseSetClaimResponse(rsp *http.Response) (*SetClaimResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &SetClaimResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseGetConfigResponse parses an HTTP response from a GetConfigWithResponse call +func ParseGetConfigResponse(rsp *http.Response) (*GetConfigResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetConfigResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Buildenv *string `json:"buildenv,omitempty"` + ChargeMode *string `json:"charge_mode,omitempty"` + DiodeCheck *bool `json:"diode_check,omitempty"` + DivertPVRatio *float32 `json:"divert_PV_ratio,omitempty"` + DivertAttackSmoothingFactor *float32 `json:"divert_attack_smoothing_factor,omitempty"` + DivertDecaySmoothingFactor *float32 `json:"divert_decay_smoothing_factor,omitempty"` + DivertEnabled *bool `json:"divert_enabled,omitempty"` + DivertMinChargeTime *float32 `json:"divert_min_charge_time,omitempty"` + EmoncmsApikey *string `json:"emoncms_apikey,omitempty"` + EmoncmsEnabled *bool `json:"emoncms_enabled,omitempty"` + EmoncmsFingerprint *string `json:"emoncms_fingerprint,omitempty"` + EmoncmsNode *string `json:"emoncms_node,omitempty"` + EmoncmsServer *string `json:"emoncms_server,omitempty"` + Espflash *float32 `json:"espflash,omitempty"` + Espinfo *string `json:"espinfo,omitempty"` + Firmware *string `json:"firmware,omitempty"` + Flags *float32 `json:"flags,omitempty"` + GfciCheck *bool `json:"gfci_check,omitempty"` + GroundCheck *bool `json:"ground_check,omitempty"` + Hostname *string `json:"hostname,omitempty"` + HttpSupportedProtocols *[]string `json:"http_supported_protocols,omitempty"` + LedBrightness *float32 `json:"led_brightness,omitempty"` + MaxCurrentHard *int `json:"max_current_hard,omitempty"` + MaxCurrentSoft *int `json:"max_current_soft,omitempty"` + MinCurrentHard *int `json:"min_current_hard,omitempty"` + MqttAnnounceTopic *string `json:"mqtt_announce_topic,omitempty"` + MqttEnabled *bool `json:"mqtt_enabled,omitempty"` + MqttGridIe *string `json:"mqtt_grid_ie,omitempty"` + MqttPass *string `json:"mqtt_pass,omitempty"` + MqttPort *int `json:"mqtt_port,omitempty"` + MqttProtocol *string `json:"mqtt_protocol,omitempty"` + MqttRejectUnauthorized *bool `json:"mqtt_reject_unauthorized,omitempty"` + MqttServer *string `json:"mqtt_server,omitempty"` + MqttSolar *string `json:"mqtt_solar,omitempty"` + MqttSupportedProtocols *[]string `json:"mqtt_supported_protocols,omitempty"` + MqttTopic *string `json:"mqtt_topic,omitempty"` + MqttUser *string `json:"mqtt_user,omitempty"` + MqttVehicleEta *string `json:"mqtt_vehicle_eta,omitempty"` + MqttVehicleRange *string `json:"mqtt_vehicle_range,omitempty"` + MqttVehicleRangeMiles *bool `json:"mqtt_vehicle_range_miles,omitempty"` + MqttVehicleSoc *string `json:"mqtt_vehicle_soc,omitempty"` + MqttVrms *string `json:"mqtt_vrms,omitempty"` + OcppChargeBoxId *string `json:"ocpp_chargeBoxId,omitempty"` + OcppEnabled *bool `json:"ocpp_enabled,omitempty"` + OcppEnergizePlug *bool `json:"ocpp_energize_plug,omitempty"` + OcppIdTag *string `json:"ocpp_idTag,omitempty"` + OcppServer *string `json:"ocpp_server,omitempty"` + OcppSuspendEvse *bool `json:"ocpp_suspend_evse,omitempty"` + Offset *int `json:"offset,omitempty"` + Ohm *string `json:"ohm,omitempty"` + OhmEnabled *bool `json:"ohm_enabled,omitempty"` + Pass *string `json:"pass,omitempty"` + PauseUsesDisabled *bool `json:"pause_uses_disabled,omitempty"` + Protocol *string `json:"protocol,omitempty"` + RelayCheck *bool `json:"relay_check,omitempty"` + Scale *int `json:"scale,omitempty"` + Service *int `json:"service,omitempty"` + SntpEnabled *bool `json:"sntp_enabled,omitempty"` + SntpHostname *string `json:"sntp_hostname,omitempty"` + Ssid *string `json:"ssid,omitempty"` + TempCheck *bool `json:"temp_check,omitempty"` + TeslaAccessToken *string `json:"tesla_access_token,omitempty"` + TeslaCreatedAt *float32 `json:"tesla_created_at,omitempty"` + TeslaEnabled *bool `json:"tesla_enabled,omitempty"` + TeslaExpiresIn *float32 `json:"tesla_expires_in,omitempty"` + TeslaRefreshToken *string `json:"tesla_refresh_token,omitempty"` + TeslaVehicleId *string `json:"tesla_vehicle_id,omitempty"` + TimeZone *string `json:"time_zone,omitempty"` + TxStartPoint *string `json:"tx_start_point,omitempty"` + VentCheck *bool `json:"vent_check,omitempty"` + Version *string `json:"version,omitempty"` + WwwPassword *string `json:"www_password,omitempty"` + WwwUsername *string `json:"www_username,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseUpdateConfigResponse parses an HTTP response from a UpdateConfigWithResponse call +func ParseUpdateConfigResponse(rsp *http.Response) (*UpdateConfigResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateConfigResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseGetEventBlockInfoResponse parses an HTTP response from a GetEventBlockInfoWithResponse call +func ParseGetEventBlockInfoResponse(rsp *http.Response) (*GetEventBlockInfoResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetEventBlockInfoResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Max *int `json:"max,omitempty"` + Min *int `json:"min,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetEventBlockResponse parses an HTTP response from a GetEventBlockWithResponse call +func ParseGetEventBlockResponse(rsp *http.Response) (*GetEventBlockResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetEventBlockResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []LogEvent + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseClearManualOverrideResponse parses an HTTP response from a ClearManualOverrideWithResponse call +func ParseClearManualOverrideResponse(rsp *http.Response) (*ClearManualOverrideResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ClearManualOverrideResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetManualOverrideResponse parses an HTTP response from a GetManualOverrideWithResponse call +func ParseGetManualOverrideResponse(rsp *http.Response) (*GetManualOverrideResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetManualOverrideResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + // `true` if the manual override is auto-released when the vehicle is + // disconnected, `false` if manual override will persist after vehicle + // disconnection. + AutoRelease *bool `json:"auto_release,omitempty"` + + // Specify the active charge current in Amps + ChargeCurrent *int `json:"charge_current,omitempty"` + + // Stop the charge after `energy_limit` Wh of energy have been transfered. + // + // > Note: Not currently implemented + EnergyLimit *int32 `json:"energy_limit,omitempty"` + + // 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 + MaxCurrent *int `json:"max_current,omitempty"` + + // Either enable charging (`active`) or block charging (`disabled`) + State *string `json:"state,omitempty"` + + // Stop the charge after the duration of the charging session has exceeded `time_limit` seconds + // + // > Note: Not currently implemented + TimeLimit *int32 `json:"time_limit,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseToggleManualOverrideResponse parses an HTTP response from a ToggleManualOverrideWithResponse call +func ParseToggleManualOverrideResponse(rsp *http.Response) (*ToggleManualOverrideResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ToggleManualOverrideResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseSetManualOverrideResponse parses an HTTP response from a SetManualOverrideWithResponse call +func ParseSetManualOverrideResponse(rsp *http.Response) (*SetManualOverrideResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &SetManualOverrideResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseListScheduleResponse parses an HTTP response from a ListScheduleWithResponse call +func ParseListScheduleResponse(rsp *http.Response) (*ListScheduleResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListScheduleResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []ScheduleEvent + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseUpdateScheduleResponse parses an HTTP response from a UpdateScheduleWithResponse call +func ParseUpdateScheduleResponse(rsp *http.Response) (*UpdateScheduleResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateScheduleResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseRemoveScheduleEventResponse parses an HTTP response from a RemoveScheduleEventWithResponse call +func ParseRemoveScheduleEventResponse(rsp *http.Response) (*RemoveScheduleEventResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &RemoveScheduleEventResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetScheduleEventResponse parses an HTTP response from a GetScheduleEventWithResponse call +func ParseGetScheduleEventResponse(rsp *http.Response) (*GetScheduleEventResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetScheduleEventResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest string + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseSetScheduleEventResponse parses an HTTP response from a SetScheduleEventWithResponse call +func ParseSetScheduleEventResponse(rsp *http.Response) (*SetScheduleEventResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &SetScheduleEventResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Message + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetStatusResponse parses an HTTP response from a GetStatusWithResponse call +func ParseGetStatusResponse(rsp *http.Response) (*GetStatusResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetStatusResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + // the value of the charge current in mA + Amp *float32 `json:"amp,omitempty"` + + // The computed avalible current for divert + AvailableCurrent *int `json:"available_current,omitempty"` + + // The divert charge rate + ChargeRate *int `json:"charge_rate,omitempty"` + + // The LCD colour + Colour *int `json:"colour,omitempty"` + + // Number of RAPI messages sent + CommSent *int `json:"comm_sent,omitempty"` + + // Number of successful RAPI messages + CommSuccess *int `json:"comm_success,omitempty"` + + // `true` if divert is active, `false` if not + DivertActive *bool `json:"divert_active,omitempty"` + + // The time since the last update of the divert feed + DivertUpdate *float32 `json:"divert_update,omitempty"` + + // The PV divert mode, `1` normal, `2` Eco + Divertmode *int `json:"divertmode,omitempty"` + + // The duration of the current charge session, in seconds + Elapsed *float32 `json:"elapsed,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + EmoncmsConnected *int `json:"emoncms_connected,omitempty"` + + // Last response message from the EmonCMS server + EmoncmsMessage *string `json:"emoncms_message,omitempty"` + + // `1`, Wired ethernet is connected, `0` no wired ethernet connection + EthConnected *int `json:"eth_connected,omitempty"` + + // `1`, if the WiFi module has negociated a connection to the OpenEVSE module, `0` not connected + EvseConnected *int `json:"evse_connected,omitempty"` + + // Number of bytes free in the ESP memory heap + FreeHeap *int `json:"free_heap,omitempty"` + + // Number of GFCI errors + Gfcicount *int `json:"gfcicount,omitempty"` + + // The latest grid +I/-E feed value received + GridIe *int `json:"grid_ie,omitempty"` + + // The current IP address of the WiFi module + Ipaddress *string `json:"ipaddress,omitempty"` + + // `1`, if the manual override is active, `0` default behaviour + ManualOverride *int `json:"manual_override,omitempty"` + + // The current mode of the EVSE + Mode *string `json:"mode,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + MqttConnected *int `json:"mqtt_connected,omitempty"` + + // `1`, network is connected, either wired or WiFi, `0` no network connection + NetConnected *int `json:"net_connected,omitempty"` + + // Number of no ground errors + Nogndcount *int `json:"nogndcount,omitempty"` + + // The current timezone + Offset *string `json:"offset,omitempty"` + + // Last status message from the OhmHour connection + OhmHour *string `json:"ohm_hour,omitempty"` + + // `1`, if there is an OTA update active, `0` if normal operation + OtaUpdate *int `json:"ota_update,omitempty"` + + // The number of posts sent to the EmonCMS server + PacketsSent *int `json:"packets_sent,omitempty"` + + // The number of successful posts to the EmonCMS server + PacketsSuccess *int `json:"packets_success,omitempty"` + + // the pilot value, in amps + Pilot *int `json:"pilot,omitempty"` + + // `1`, if RAPI messages have successfully been sent to the OpenEVSE module, `0` not connected + RapiConnected *int `json:"rapi_connected,omitempty"` + + // The current service level + ServiceLevel *int `json:"service_level,omitempty"` + + // The computed smoothed available current for divert + SmoothedAvailableCurrent *int `json:"smoothed_available_current,omitempty"` + + // The latest solar feed value received + Solar *int `json:"solar,omitempty"` + + // WiFi RSSI signal strength + Srssi *int `json:"srssi,omitempty"` + + // The EVSE status + State *int `json:"state,omitempty"` + + // Number of stuck relay errors + Stuckcount *int `json:"stuckcount,omitempty"` + + // the derived temperature, in 1/10th °C + Temp *float32 `json:"temp,omitempty"` + + // The current time on the WiFi module + Time *string `json:"time,omitempty"` + + // `1`, if a vehicle id connected to the EVSE, `0` not connected + Vehicle *int `json:"vehicle,omitempty"` + + // the charge voltage, read form the EVSE if supported, or supplied via MQTT or other external source + Voltage *float32 `json:"voltage,omitempty"` + + // The total amount of energy transfered, in W/hour + Watthour *int `json:"watthour,omitempty"` + + // The amount of energy transfered in this charge session, in W/sec + Wattsec *float32 `json:"wattsec,omitempty"` + + // `1`, WiFi is connected, `0` no WiFi connection + WifiClientConnected *int `json:"wifi_client_connected,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetTeslaVehiclesResponse parses an HTTP response from a GetTeslaVehiclesWithResponse call +func ParseGetTeslaVehiclesResponse(rsp *http.Response) (*GetTeslaVehiclesResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetTeslaVehiclesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Count float32 `json:"count"` + Vehicles []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"vehicles"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseStatusUpdatesResponse parses an HTTP response from a StatusUpdatesWithResponse call +func ParseStatusUpdatesResponse(rsp *http.Response) (*StatusUpdatesResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &StatusUpdatesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + // the value of the charge current in mA + Amp *float32 `json:"amp,omitempty"` + + // The computed avalible current for divert + AvailableCurrent *int `json:"available_current,omitempty"` + + // The divert charge rate + ChargeRate *int `json:"charge_rate,omitempty"` + + // The LCD colour + Colour *int `json:"colour,omitempty"` + + // Number of RAPI messages sent + CommSent *int `json:"comm_sent,omitempty"` + + // Number of successful RAPI messages + CommSuccess *int `json:"comm_success,omitempty"` + + // `true` if divert is active, `false` if not + DivertActive *bool `json:"divert_active,omitempty"` + + // The time since the last update of the divert feed + DivertUpdate *float32 `json:"divert_update,omitempty"` + + // The PV divert mode, `1` normal, `2` Eco + Divertmode *int `json:"divertmode,omitempty"` + + // The duration of the current charge session, in seconds + Elapsed *float32 `json:"elapsed,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + EmoncmsConnected *int `json:"emoncms_connected,omitempty"` + + // Last response message from the EmonCMS server + EmoncmsMessage *string `json:"emoncms_message,omitempty"` + + // `1`, Wired ethernet is connected, `0` no wired ethernet connection + EthConnected *int `json:"eth_connected,omitempty"` + + // `1`, if the WiFi module has negociated a connection to the OpenEVSE module, `0` not connected + EvseConnected *int `json:"evse_connected,omitempty"` + + // Number of bytes free in the ESP memory heap + FreeHeap *int `json:"free_heap,omitempty"` + + // Number of GFCI errors + Gfcicount *int `json:"gfcicount,omitempty"` + + // The latest grid +I/-E feed value received + GridIe *int `json:"grid_ie,omitempty"` + + // The current IP address of the WiFi module + Ipaddress *string `json:"ipaddress,omitempty"` + + // `1`, if the manual override is active, `0` default behaviour + ManualOverride *int `json:"manual_override,omitempty"` + + // The current mode of the EVSE + Mode *string `json:"mode,omitempty"` + + // `1`, if connected to an EmonCMS server, `0` not connected + MqttConnected *int `json:"mqtt_connected,omitempty"` + + // `1`, network is connected, either wired or WiFi, `0` no network connection + NetConnected *int `json:"net_connected,omitempty"` + + // Number of no ground errors + Nogndcount *int `json:"nogndcount,omitempty"` + + // The current timezone + Offset *string `json:"offset,omitempty"` + + // Last status message from the OhmHour connection + OhmHour *string `json:"ohm_hour,omitempty"` + + // `1`, if there is an OTA update active, `0` if normal operation + OtaUpdate *int `json:"ota_update,omitempty"` + + // The number of posts sent to the EmonCMS server + PacketsSent *int `json:"packets_sent,omitempty"` + + // The number of successful posts to the EmonCMS server + PacketsSuccess *int `json:"packets_success,omitempty"` + + // the pilot value, in amps + Pilot *int `json:"pilot,omitempty"` + + // `1`, if RAPI messages have successfully been sent to the OpenEVSE module, `0` not connected + RapiConnected *int `json:"rapi_connected,omitempty"` + + // The current service level + ServiceLevel *int `json:"service_level,omitempty"` + + // The computed smoothed available current for divert + SmoothedAvailableCurrent *int `json:"smoothed_available_current,omitempty"` + + // The latest solar feed value received + Solar *int `json:"solar,omitempty"` + + // WiFi RSSI signal strength + Srssi *int `json:"srssi,omitempty"` + + // The EVSE status + State *int `json:"state,omitempty"` + + // Number of stuck relay errors + Stuckcount *int `json:"stuckcount,omitempty"` + + // the derived temperature, in 1/10th °C + Temp *float32 `json:"temp,omitempty"` + + // The current time on the WiFi module + Time *string `json:"time,omitempty"` + + // `1`, if a vehicle id connected to the EVSE, `0` not connected + Vehicle *int `json:"vehicle,omitempty"` + + // the charge voltage, read form the EVSE if supported, or supplied via MQTT or other external source + Voltage *float32 `json:"voltage,omitempty"` + + // The total amount of energy transfered, in W/hour + Watthour *int `json:"watthour,omitempty"` + + // The amount of energy transfered in this charge session, in W/sec + Wattsec *float32 `json:"wattsec,omitempty"` + + // `1`, WiFi is connected, `0` no WiFi connection + WifiClientConnected *int `json:"wifi_client_connected,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} diff --git a/charger/openevse/api.yaml b/charger/openevse/api.yaml new file mode 100644 index 000000000..fcc8e6ca8 --- /dev/null +++ b/charger/openevse/api.yaml @@ -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 diff --git a/charger/openevse/generate.go b/charger/openevse/generate.go new file mode 100644 index 000000000..4bc5b3992 --- /dev/null +++ b/charger/openevse/generate.go @@ -0,0 +1,3 @@ +package openevse + +// go:generate sh -c "oapi-codegen -package openevse -old-config-style -generate types,client api.yaml > api.go" diff --git a/charger/openevse/models/Claim.yaml b/charger/openevse/models/Claim.yaml new file mode 100644 index 000000000..2c987237f --- /dev/null +++ b/charger/openevse/models/Claim.yaml @@ -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 diff --git a/charger/openevse/models/Config.yaml b/charger/openevse/models/Config.yaml new file mode 100644 index 000000000..5d9ad1cd2 --- /dev/null +++ b/charger/openevse/models/Config.yaml @@ -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 diff --git a/charger/openevse/models/EvseState.yaml b/charger/openevse/models/EvseState.yaml new file mode 100644 index 000000000..e5c2ebc5a --- /dev/null +++ b/charger/openevse/models/EvseState.yaml @@ -0,0 +1,6 @@ +title: EvseState +type: string +x-tags: + - Claims + - Status +description: Either enable charging (`active`) or block charging (`disabled`) diff --git a/charger/openevse/models/Properties.yaml b/charger/openevse/models/Properties.yaml new file mode 100644 index 000000000..77e24e132 --- /dev/null +++ b/charger/openevse/models/Properties.yaml @@ -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. diff --git a/charger/openevse/models/Status.yaml b/charger/openevse/models/Status.yaml new file mode 100644 index 000000000..534182930 --- /dev/null +++ b/charger/openevse/models/Status.yaml @@ -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 diff --git a/charger/openevse/types.go b/charger/openevse/types.go new file mode 100644 index 000000000..238157e9d --- /dev/null +++ b/charger/openevse/types.go @@ -0,0 +1,6 @@ +package openevse + +type RAPIResponse struct { + Cmd string `json:"cmd"` + Ret string `json:"ret"` +} diff --git a/charger/openevse_decorators.go b/charger/openevse_decorators.go new file mode 100644 index 000000000..47adc57ed --- /dev/null +++ b/charger/openevse_decorators.go @@ -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) +} diff --git a/go.mod b/go.mod index 8ac8d4d55..298082a0f 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 0dd39dbe6..6df5528ee 100644 --- a/go.sum +++ b/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= diff --git a/templates/definition/charger/openevse.yaml b/templates/definition/charger/openevse.yaml new file mode 100644 index 000000000..13bce2935 --- /dev/null +++ b/templates/definition/charger/openevse.yaml @@ -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 }} diff --git a/templates/docs/charger/openevse_0.yaml b/templates/docs/charger/openevse_0.yaml new file mode 100644 index 000000000..40cd0d0e4 --- /dev/null +++ b/templates/docs/charger/openevse_0.yaml @@ -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 diff --git a/templates/evcc.io/brands.json b/templates/evcc.io/brands.json index ec8afb0c0..c06a511a6 100644 --- a/templates/evcc.io/brands.json +++ b/templates/evcc.io/brands.json @@ -25,6 +25,7 @@ "KSE", "Mennekes", "NRGKick", + "OpenEVSE", "openWB", "Optec", "PC Electric",