Repository: evcc-io/evcc
Pull request #10131 (2023-10-01 10:49:37)

Mqtt: limit number of inflight token waits
Fix https://github.com/evcc-io/evcc/issues/10095

/cc @GrimmiMeloni 


Patch:
diff --git a/charger/mennekes.go b/charger/mennekes.go
new file mode 100644
index 00000000..c7d35098
--- /dev/null
+++ b/charger/mennekes.go
@@ -0,0 +1,291 @@
+package charger
+
+// LICENSE
+
+// Copyright (c) 2023 premultiply
+
+// This module is NOT covered by the MIT license. All rights reserved.
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import (
+	"encoding/binary"
+	"fmt"
+	"math"
+	"time"
+
+	"github.com/evcc-io/evcc/api"
+	"github.com/evcc-io/evcc/util"
+	"github.com/evcc-io/evcc/util/modbus"
+	"github.com/evcc-io/evcc/util/sponsor"
+	"github.com/volkszaehler/mbmd/encoding"
+)
+
+// Mennekes is an api.Charger implementation
+type Mennekes struct {
+	log  *util.Logger
+	conn *modbus.Connection
+}
+
+const (
+	mennekesRegModbusVersion        = 0x0000 // uint16
+	mennekesRegFirmwareVersion      = 0x0001 // ascii[16]
+	mennekesRegSerialNumber         = 0x0013 // ascii[16]
+	mennekesRegEvseState            = 0x0100 // uint16
+	mennekesRegAuthorizationStatus  = 0x0101 // uint16
+	mennekesRegCpState              = 0x0108 // uint16
+	mennekesRegChargingCurrentEM    = 0x0302 // float32
+	mennekesRegPhaseOptionsHW       = 0x030C // uint16
+	mennekesRegGridPhasesConnected  = 0x0311 // uint16
+	mennekesRegAuthorization        = 0x0312 // uint16
+	mennekesRegCurrents             = 0x0500 // float32[3]
+	mennekesRegVoltages             = 0x0506 // float32[3]
+	mennekesRegPower                = 0x0512 // float32
+	mennekesRegChargedEnergySession = 0x0B02 // float32
+	mennekesRegDurationSession      = 0x0B04 // uint32
+	mennekesRegHeartbeat            = 0x0D00 // uint16
+	mennekesRegRequestedPhases      = 0x0D04 // uint16
+	mennekesRegChargingReleaseEM    = 0x0D05 // uint16
+	mennekesRegChargedEnergyTotal   = 0x1000 // float32
+
+	mennekesAllowed           = 1
+	mennekesHeartbeatInterval = 10
+	mennekesHeartbeatToken    = 0x55AA // 21930
+)
+
+func init() {
+	registry.Add("mennekes", NewMennekesFromConfig)
+}
+
+// NewMennekesFromConfig creates a new Mennekes ModbusTCP charger
+func NewMennekesFromConfig(other map[string]interface{}) (api.Charger, error) {
+	cc := struct {
+		modbus.Settings `mapstructure:",squash"`
+		Timeout         time.Duration
+	}{
+		Settings: modbus.Settings{
+			Baudrate: 57600,
+			Comset:   "8N2",
+			ID:       50,
+		},
+	}
+
+	if err := util.DecodeOther(other, &cc); err != nil {
+		return nil, err
+	}
+
+	return NewMennekes(cc.URI, cc.Device, cc.Comset, cc.Baudrate, modbus.ProtocolFromRTU(cc.RTU), cc.ID, cc.Timeout)
+}
+
+// NewMennekes creates Mennekes charger
+func NewMennekes(uri, device, comset string, baudrate int, proto modbus.Protocol, slaveID uint8, timeout time.Duration) (api.Charger, error) {
+	conn, err := modbus.NewConnection(uri, device, comset, baudrate, proto, slaveID)
+	if err != nil {
+		return nil, err
+	}
+
+	if timeout > 0 {
+		conn.Timeout(timeout)
+	}
+
+	if !sponsor.IsAuthorized() {
+		return nil, api.ErrSponsorRequired
+	}
+
+	log := util.NewLogger("mennekes")
+	conn.Logger(log.TRACE)
+
+	wb := &Mennekes{
+		log:  log,
+		conn: conn,
+	}
+
+	// failsafe
+	go wb.heartbeat(time.Duration(mennekesHeartbeatInterval) * time.Second)
+
+	return wb, err
+}
+
+func (wb *Mennekes) heartbeat(timeout time.Duration) {
+	for range time.Tick(timeout) {
+		if _, err := wb.conn.WriteSingleRegister(mennekesRegHeartbeat, mennekesHeartbeatToken); err != nil {
+			wb.log.ERROR.Println("heartbeat:", err)
+		}
+	}
+}
+
+// Status implements the api.Charger interface
+func (wb *Mennekes) Status() (api.ChargeStatus, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegEvseState, 1)
+	if err != nil {
+		return api.StatusNone, err
+	}
+
+	switch status := encoding.Uint16(b); status {
+	case 1:
+		return api.StatusA, nil
+
+	case 2, 3, 4:
+		return api.StatusB, nil
+
+	case 5:
+		return api.StatusC, nil
+
+	default:
+		return api.StatusNone, fmt.Errorf("invalid status: %d", status)
+	}
+}
+
+// Enabled implements the api.Charger interface
+func (wb *Mennekes) Enabled() (bool, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegChargingReleaseEM, 1)
+	if err != nil {
+		return false, err
+	}
+	u := encoding.Uint16(b)
+	return u == mennekesAllowed, nil
+}
+
+// Enable implements the api.Charger interface
+func (wb *Mennekes) Enable(enable bool) error {
+	var u uint16
+	if enable {
+		u = 1
+	}
+	_, err := wb.conn.WriteSingleRegister(mennekesRegChargingReleaseEM, u)
+	return err
+}
+
+// MaxCurrent implements the api.Charger interface
+func (wb *Mennekes) MaxCurrent(current int64) error {
+	return wb.MaxCurrentMillis(float64(current))
+}
+
+var _ api.ChargerEx = (*Mennekes)(nil)
+
+// MaxCurrentMillis implements the api.ChargerEx interface
+func (wb *Mennekes) MaxCurrentMillis(current float64) error {
+	b := make([]byte, 4)
+
+	// LSW first
+	u := math.Float32bits(float32(current))
+	binary.BigEndian.PutUint16(b, uint16(u))
+	binary.BigEndian.PutUint16(b[2:], uint16(u>>16))
+
+	_, err := wb.conn.WriteMultipleRegisters(mennekesRegChargingCurrentEM, 2, b)
+	return err
+}
+
+// CurrentPower implements the api.Meter interface
+func (wb *Mennekes) CurrentPower() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegPower, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(encoding.Float32LswFirst(b)) * 1e3, nil
+}
+
+var _ api.MeterEnergy = (*Mennekes)(nil)
+
+// TotalEnergy implements the api.MeterEnergy interface
+func (wb *Mennekes) TotalEnergy() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegChargedEnergyTotal, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(encoding.Uint32(b)), nil
+}
+
+var _ api.PhaseCurrents = (*Mennekes)(nil)
+
+// Currents implements the api.PhaseCurrents interface
+func (wb *Mennekes) Currents() (float64, float64, float64, error) {
+	return wb.getPhaseValues(mennekesRegCurrents)
+}
+
+var _ api.PhaseVoltages = (*Mennekes)(nil)
+
+// Voltages implements the api.PhaseVoltages interface
+func (wb *Mennekes) Voltages() (float64, float64, float64, error) {
+	return wb.getPhaseValues(mennekesRegVoltages)
+}
+
+// getPhaseValues returns 3 sequential phase values
+func (wb *Mennekes) getPhaseValues(reg uint16) (float64, float64, float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(reg, 6)
+	if err != nil {
+		return 0, 0, 0, err
+	}
+
+	var res [3]float64
+	for i := 0; i < 3; i++ {
+		res[i] = float64(encoding.Float32LswFirst(b[4*i:]))
+	}
+
+	return res[0], res[1], res[2], nil
+}
+
+/*
+var _ api.ChargeRater = (*Mennekes)(nil)
+
+// ChargedEnergy implements the api.MeterEnergy interface
+func (wb *Mennekes) ChargedEnergy() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegChargedEnergySession, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(encoding.Float32LswFirst(b)), err
+}
+
+var _ api.ChargeTimer = (*Mennekes)(nil)
+
+// ChargingTime implements the api.ChargeTimer interface
+func (wb *Mennekes) ChargingTime() (time.Duration, error) {
+	b, err := wb.conn.ReadHoldingRegisters(mennekesRegDurationSession, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return time.Duration(encoding.Uint32(b)) * time.Second, nil
+}
+*/
+
+var _ api.PhaseSwitcher = (*Mennekes)(nil)
+
+// Phases1p3p implements the api.PhaseSwitcher interface
+func (wb *Mennekes) Phases1p3p(phases int) error {
+	var u uint16
+	if phases == 3 {
+		u = 1
+	}
+
+	_, err := wb.conn.WriteSingleRegister(mennekesRegRequestedPhases, u)
+	return err
+}
+
+var _ api.Diagnosis = (*Mennekes)(nil)
+
+// Diagnose implements the api.Diagnosis interface
+func (wb *Mennekes) Diagnose() {
+	if b, err := wb.conn.ReadHoldingRegisters(mennekesRegModbusVersion, 1); err == nil {
+		fmt.Printf("\tModbus:\t%d\n", encoding.Uint16(b))
+	}
+	if b, err := wb.conn.ReadHoldingRegisters(mennekesRegFirmwareVersion, 8); err == nil {
+		fmt.Printf("\tFirmware:\t%s\n", encoding.StringLsbFirst(b))
+	}
+	if b, err := wb.conn.ReadHoldingRegisters(mennekesRegSerialNumber, 8); err == nil {
+		fmt.Printf("\tSerial:\t%s\n", encoding.StringLsbFirst(b))
+	}
+}
diff --git a/charger/openevse.go b/charger/openevse.go
index 56f713a5..c56a93dd 100644
--- a/charger/openevse.go
+++ b/charger/openevse.go
@@ -1,33 +1,35 @@
 package charger
 
 import (
-	"context"
 	"errors"
 	"fmt"
+	"net/http"
 	"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/provider"
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/request"
+	"github.com/evcc-io/evcc/util/transport"
 )
 
 // OpenEVSE charger implementation
 type OpenEVSE struct {
+	*request.Helper
 	uri     string
-	api     *openevse.ClientWithResponses
-	helper  *request.Helper
-	timeout time.Duration
+	statusG provider.Cacheable[openevse.Status]
+	current int
+	enabled bool
 }
 
 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"
+// go:generate go run ../cmd/tools/decorate.go -f decorateOpenEVSE -b ""*OpenEVSE" -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
 
 // NewOpenEVSEFromConfig creates an OpenEVSE charger from generic config
 func NewOpenEVSEFromConfig(other map[string]interface{}) (api.Charger, error) {
@@ -35,9 +37,9 @@ func NewOpenEVSEFromConfig(other map[string]interface{}) (api.Charger, error) {
 		URI      string
 		User     string
 		Password string
-		Timeout  time.Duration
+		Cache    time.Duration
 	}{
-		Timeout: request.Timeout,
+		Cache: time.Second,
 	}
 
 	if err := util.DecodeOther(other, &cc); err != nil {
@@ -48,34 +50,31 @@ func NewOpenEVSEFromConfig(other map[string]interface{}) (api.Charger, error) {
 		return nil, errors.New("missing uri")
 	}
 
-	return NewOpenEVSE(cc.URI, cc.User, cc.Password, cc.Timeout)
+	return NewOpenEVSE(cc.URI, cc.User, cc.Password, cc.Cache)
 }
 
 // NewOpenEVSE creates OpenEVSE charger
-func NewOpenEVSE(uri, user, password string, timeout time.Duration) (api.Charger, error) {
-	log := util.NewLogger("openevse").Redact(user, password)
+func NewOpenEVSE(uri, user, password string, cache time.Duration) (api.Charger, error) {
+	basicAuth := transport.BasicAuthHeader(user, password)
+	log := util.NewLogger("openevse").Redact(user, password, basicAuth)
+
 	c := &OpenEVSE{
-		helper:  request.NewHelper(log),
-		uri:     uri,
-		timeout: timeout,
+		Helper: request.NewHelper(log),
+		uri:    util.DefaultScheme(strings.TrimSuffix(uri, "/"), "http"),
 	}
 
-	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))
+		c.Client.Transport = transport.BasicAuth(user, password, c.Client.Transport)
 	}
 
-	var err error
-	c.api, err = openevse.NewClientWithResponses(uri, options...)
-	if err != nil {
-		return c, err
-	}
+	c.statusG = provider.ResettableCached(func() (openevse.Status, error) {
+		var res openevse.Status
+
+		uri := fmt.Sprintf("%s/status", c.uri)
+		err := c.GetJSON(uri, &res)
+
+		return res, err
+	}, cache)
 
 	var phases1p3p func(int) error
 	if err := c.hasPhaseSwitchCapabilities(); err == nil {
@@ -87,16 +86,30 @@ func NewOpenEVSE(uri, user, password string, timeout time.Duration) (api.Charger
 		}
 	}
 
-	return decorateOpenEVSE(c, phases1p3p), err
+	return decorateOpenEVSE(c, phases1p3p), nil
 }
 
-func (c *OpenEVSE) requestContextWithTimeout() (context.Context, context.CancelFunc) {
-	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
-	return ctx, cancel
-}
+func (c *OpenEVSE) setOverride() error {
+	var data openevse.Override
+	uri := fmt.Sprintf("%s/override", c.uri)
 
-func (c *OpenEVSE) hasPhaseSwitchCapabilities() error {
-	return c.rapiCommand("$G7")
+	if err := c.GetJSON(uri, &data); err != nil {
+		return err
+	}
+
+	state := openevse.Disabled
+	if c.enabled {
+		state = openevse.Enabled
+	}
+	data.State = &state
+	data.MaxCurrent = &c.current
+
+	req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
+	if err == nil {
+		_, err = c.DoBody(req)
+	}
+
+	return err
 }
 
 func (c *OpenEVSE) rapiCommand(command string) error {
@@ -106,7 +119,7 @@ func (c *OpenEVSE) rapiCommand(command string) error {
 
 	uri := fmt.Sprintf("%s/r?json=1&rapi=%s", c.uri, url.QueryEscape(command))
 
-	err := c.helper.GetJSON(uri, &res)
+	err := c.GetJSON(uri, &res)
 	if err == nil && !strings.HasPrefix(res.Ret, "$OK") {
 		err = fmt.Errorf("rapi command failed: %s", res.Ret)
 	}
@@ -114,32 +127,13 @@ func (c *OpenEVSE) rapiCommand(command string) error {
 	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) hasPhaseSwitchCapabilities() error {
+	return c.rapiCommand("$G7")
 }
 
+// Status implements the api.Charger interface
 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
-	}
-
+	res, err := c.statusG.Get()
 	/*
 		0: "unknown",
 		1: "not connected",
@@ -157,20 +151,20 @@ func (c *OpenEVSE) Status() (api.ChargeStatus, error) {
 		255: "disabled"
 	*/
 
-	switch state := *res.JSON200.State; state {
+	switch state := *res.State; state {
 	case 1:
-		return api.StatusA, nil
+		return api.StatusA, err
 	case 2, 254, 255:
-		if connected := *res.JSON200.Vehicle != 0; connected {
-			return api.StatusB, nil
+		if *res.Vehicle == 1 {
+			return api.StatusB, err
 		}
-		return api.StatusA, nil
+		return api.StatusA, err
 	case 3:
-		return api.StatusC, nil
+		return api.StatusC, err
 	case 4:
-		return api.StatusD, nil
+		return api.StatusD, err
 	case 5, 6, 7, 8, 9, 10, 11:
-		return api.StatusF, nil
+		return api.StatusF, err
 	default:
 		return api.StatusNone, fmt.Errorf("unknown EVSE state: %d", state)
 	}
@@ -178,79 +172,64 @@ func (c *OpenEVSE) Status() (api.ChargeStatus, error) {
 
 // Enabled implements the api.Charger interface
 func (c *OpenEVSE) Enabled() (bool, error) {
-	ctx, cancel := c.requestContextWithTimeout()
-	defer cancel()
-	overrideResp, err := c.api.GetStatusWithResponse(ctx)
-
-	if err != nil {
-		return false, err
-	}
-
-	if overrideResp.JSON200 != nil && overrideResp.JSON200.State != nil {
-		status := *overrideResp.JSON200.Status
-
-		switch status {
-		case "disabled":
-			return false, nil
-		case "enabled", "active":
-			return true, nil
-		default:
-			return false, fmt.Errorf("unknown EVSE status: %s", status)
-		}
-	}
-
-	// no override:
-	return false, fmt.Errorf("invalid EVSE status")
+	res, err := c.statusG.Get()
+	return *res.Status == openevse.Enabled, err
 }
 
 // Enable implements the api.Charger interface
 func (c *OpenEVSE) Enable(enable bool) error {
-	return c.SetManualOverride(enable)
+	c.enabled = enable
+	return c.setOverride()
 }
 
 // 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
+	c.current = int(current)
+	return c.setOverride()
 }
 
 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)
+	res, err := c.statusG.Get()
 	if err != nil {
 		return 0, err
 	}
 
-	return float64(*resp.JSON200.Wattsec) / 3600 / 1e3, nil
+	return *res.SessionEnergy / 1e3, err
+}
+
+var _ api.ChargeTimer = (*OpenEVSE)(nil)
+
+func (c *OpenEVSE) ChargingTime() (time.Duration, error) {
+	res, err := c.statusG.Get()
+	if err != nil {
+		return 0, err
+	}
+	return time.Duration(*res.SessionElapsed) * time.Second, err
 }
 
 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)
+	res, err := c.statusG.Get()
 	if err != nil {
 		return 0, err
 	}
 
-	return float64(*resp.JSON200.Watthour) / 1e3, nil
+	return *res.TotalEnergy, err
+}
+
+var _ api.Meter = (*OpenEVSE)(nil)
+
+func (c *OpenEVSE) CurrentPower() (float64, error) {
+	res, err := c.statusG.Get()
+	if err != nil {
+		return 0, err
+	}
+	return *res.Power, err
 }
 
 // phases1p3p implements the api.ChargePhases interface
diff --git a/charger/openevse/api.go b/charger/openevse/api.go
deleted file mode 100644
index 08414cf2..00000000
--- a/charger/openevse/api.go
+++ /dev/null
@@ -1,3496 +0,0 @@
-// 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 state
-		State *int `json:"state,omitempty"`
-
-		// The EVSE status
-		Status *string `json:"status,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 *float32 `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 *float32 `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 state
-			State *int `json:"state,omitempty"`
-
-			// The EVSE status
-			Status *string `json:"status,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 *float32 `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 *float32 `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
deleted file mode 100644
index 5a069984..00000000
--- a/charger/openevse/api.yaml
+++ /dev/null
@@ -1,644 +0,0 @@
-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
deleted file mode 100644
index 4bc5b399..00000000
--- a/charger/openevse/generate.go
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index 2c987237..00000000
--- a/charger/openevse/models/Claim.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644
index 5d9ad1cd..00000000
--- a/charger/openevse/models/Config.yaml
+++ /dev/null
@@ -1,352 +0,0 @@
-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
deleted file mode 100644
index e5c2ebc5..00000000
--- a/charger/openevse/models/EvseState.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-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
deleted file mode 100644
index 77e24e13..00000000
--- a/charger/openevse/models/Properties.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-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
deleted file mode 100644
index 53418293..00000000
--- a/charger/openevse/models/Status.yaml
+++ /dev/null
@@ -1,136 +0,0 @@
-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
index 238157e9..11a3492f 100644
--- a/charger/openevse/types.go
+++ b/charger/openevse/types.go
@@ -1,6 +1,30 @@
 package openevse
 
-type RAPIResponse struct {
-	Cmd string `json:"cmd"`
-	Ret string `json:"ret"`
+const (
+	Enabled  = "active"
+	Disabled = "disabled"
+)
+
+// Only keep the interesting properties from the status endpoint
+type Status struct {
+	Amp            *float64 `json:"amp,omitempty"`             // the value of the charge current in mA
+	Elapsed        *float64 `json:"elapsed,omitempty"`         // current session duration in seconds
+	ManualOverride *int     `json:"manual_override,omitempty"` // 1 = active, 0 = default
+	Mode           *string  `json:"mode,omitempty"`            // The current mode of the EVSE
+	Pilot          *int     `json:"pilot,omitempty"`           // the pilot value, in amps
+	Power          *float64 `json:"power,omitempty"`           // apparent power in watts
+	SessionEnergy  *float64 `json:"session_energy"`            // The total amount of energy accumulated for current session (in wh)
+	SessionElapsed *int     `json:"session_elapsed"`           // duration of this charging session in seconds
+	State          *int     `json:"state,omitempty"`           // evse state 1=A 2=B 3=C 4=D 5-11=F 254=sleeping 255=disabled
+	Status         *string  `json:"status,omitempty"`          // active, disabled, none, unknown
+	TotalEnergy    *float64 `json:"total_energy"`              // The total amount of energy accumulated (in kwh)
+	Vehicle        *int     `json:"vehicle,omitempty"`         // 0=not connected, 1=connected
+	Voltage        *float64 `json:"voltage,omitempty"`         // supplied via MQTT/Tesla/HTTP or assume a default
+}
+
+type Override struct {
+	State         *string `json:"state,omitempty"`          // Either enable charging (active) or block charging (disabled)
+	ChargeCurrent *int    `json:"charge_current,omitempty"` // Specify the active charge current in Amps >= 0
+	MaxCurrent    *int    `json:"max_current,omitempty"`    // Maximum current, primarily for load sharing situations
+	AutoRelease   *bool   `json:"auto_release,omitempty"`
 }
diff --git a/charger/openwb.go b/charger/openwb.go
index 4b0d765d..8f67e0ca 100644
--- a/charger/openwb.go
+++ b/charger/openwb.go
@@ -177,12 +177,7 @@ func (m *OpenWB) Enable(enable bool) error {
 }
 
 func (m *OpenWB) Enabled() (bool, error) {
-	enabled, err := verifyEnabled(m, m.enabled)
-	if err == nil {
-		m.enabled = enabled
-	}
-
-	return enabled, err
+	return verifyEnabled(m, m.enabled)
 }
 
 func (m *OpenWB) Status() (api.ChargeStatus, error) {
diff --git a/charger/twc3.go b/charger/twc3.go
index c086ca9b..0914f1a6 100644
--- a/charger/twc3.go
+++ b/charger/twc3.go
@@ -91,12 +91,7 @@ func NewTwc3FromConfig(other map[string]interface{}) (api.Charger, error) {
 
 // Enabled implements the api.Charger interface
 func (c *Twc3) Enabled() (bool, error) {
-	enabled, err := verifyEnabled(c, c.enabled)
-	if err == nil {
-		c.enabled = enabled
-	}
-
-	return enabled, err
+	return verifyEnabled(c, c.enabled)
 }
 
 // Enable implements the api.Charger interface
diff --git a/charger/victron.go b/charger/victron.go
new file mode 100644
index 00000000..989a2268
--- /dev/null
+++ b/charger/victron.go
@@ -0,0 +1,150 @@
+package charger
+
+// LICENSE
+
+// Copyright (c) 2023 andig
+
+// This module is NOT covered by the MIT license. All rights reserved.
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import (
+	"encoding/binary"
+	"errors"
+
+	"github.com/evcc-io/evcc/api"
+	"github.com/evcc-io/evcc/util"
+	"github.com/evcc-io/evcc/util/modbus"
+	"github.com/evcc-io/evcc/util/sponsor"
+)
+
+// Victron charger implementation
+type Victron struct {
+	conn *modbus.Connection
+}
+
+const (
+	victronRegMode       = 3815
+	victronRegEnergy     = 3816
+	victronRegPower      = 3821
+	victronRegStatus     = 3824
+	victronRegSetCurrent = 3825
+	victronRegEnabled    = 3826
+)
+
+func init() {
+	registry.Add("victron", NewVictronFromConfig)
+}
+
+// NewVictronFromConfig creates a ABB charger from generic config
+func NewVictronFromConfig(other map[string]interface{}) (api.Charger, error) {
+	cc := modbus.TcpSettings{
+		ID: 100,
+	}
+
+	if err := util.DecodeOther(other, &cc); err != nil {
+		return nil, err
+	}
+
+	return NewVictron(cc.URI, cc.ID)
+}
+
+// NewVictron creates Victron charger
+func NewVictron(uri string, slaveID uint8) (api.Charger, error) {
+	conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, slaveID)
+	if err != nil {
+		return nil, err
+	}
+
+	if !sponsor.IsAuthorized() {
+		return nil, api.ErrSponsorRequired
+	}
+
+	log := util.NewLogger("victron")
+	conn.Logger(log.TRACE)
+
+	wb := &Victron{
+		conn: conn,
+	}
+
+	b, err := wb.conn.ReadHoldingRegisters(victronRegMode, 1)
+	if err != nil {
+		return nil, err
+	}
+
+	if binary.BigEndian.Uint16(b) != 0 {
+		return nil, errors.New("charger must be in manual mode")
+	}
+
+	return wb, err
+}
+
+// Status implements the api.Charger interface
+func (wb *Victron) Status() (api.ChargeStatus, error) {
+	b, err := wb.conn.ReadHoldingRegisters(victronRegStatus, 1)
+	if err != nil {
+		return api.StatusNone, err
+	}
+
+	return api.ChargeStatusString(string('A' + rune(binary.BigEndian.Uint16(b))))
+}
+
+// Enabled implements the api.Charger interface
+func (wb *Victron) Enabled() (bool, error) {
+	b, err := wb.conn.ReadHoldingRegisters(victronRegEnabled, 1)
+	if err != nil {
+		return false, err
+	}
+
+	return binary.BigEndian.Uint16(b) != 0, nil
+}
+
+// Enable implements the api.Charger interface
+func (wb *Victron) Enable(enable bool) error {
+	var u uint16
+	if enable {
+		u = 1
+	}
+
+	_, err := wb.conn.WriteSingleRegister(victronRegEnabled, u)
+	return err
+}
+
+// MaxCurrent implements the api.Charger interface
+func (wb *Victron) MaxCurrent(current int64) error {
+	_, err := wb.conn.WriteSingleRegister(victronRegSetCurrent, uint16(current))
+	return err
+}
+
+var _ api.Meter = (*Victron)(nil)
+
+// CurrentPower implements the api.Meter interface
+func (wb *Victron) CurrentPower() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(victronRegPower, 1)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(binary.BigEndian.Uint16(b)), nil
+}
+
+var _ api.ChargeRater = (*Victron)(nil)
+
+// ChargedEnergy implements the api.MeterEnergy interface
+func (wb *Victron) ChargedEnergy() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(victronRegEnergy, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(binary.BigEndian.Uint32(b)) / 100, nil
+}
diff --git a/core/loadpoint.go b/core/loadpoint.go
index a493cc68..6030a474 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -639,22 +639,24 @@ func (lp *Loadpoint) syncCharger() error {
 		return err
 	}
 
-	defer func() {
-		lp.enabled = enabled
-		lp.publish("enabled", lp.enabled)
-	}()
+	if lp.guardGracePeriodElapsed() {
+		defer func() {
+			lp.enabled = enabled
+			lp.publish("enabled", lp.enabled)
+		}()
+	}
 
 	if !enabled && lp.charging() {
+		lp.log.WARN.Println("charger logic error: disabled but charging")
+		enabled = true // treat as enabled when charging
 		if lp.guardGracePeriodElapsed() {
-			lp.log.WARN.Println("charger logic error: disabled but charging")
-		}
-		enabled = true                                  // treat as enabled when charging
-		if err := lp.charger.Enable(true); err != nil { // also enable charger to correct internal state
-			return err
+			if err := lp.charger.Enable(true); err != nil { // also enable charger to correct internal state
+				return err
+			}
+			lp.elapseGuard()
+			lp.elapsePVTimer()
+			return nil
 		}
-		lp.elapseGuard()
-		lp.elapsePVTimer()
-		return nil
 	}
 
 	// status in sync
@@ -1045,6 +1047,10 @@ func (lp *Loadpoint) pvScalePhases(availablePower, minCurrent, maxCurrent float6
 	if targetCurrent := powerToCurrent(availablePower, activePhases); targetCurrent < minCurrent && activePhases > 1 && lp.ConfiguredPhases < 3 {
 		lp.log.DEBUG.Printf("available power %.0fW < %.0fW min %dp threshold", availablePower, float64(activePhases)*Voltage*minCurrent, activePhases)
 
+		if !lp.charging() { // scale immediately if not charging
+			lp.phaseTimer = elapsed
+		}
+
 		if lp.phaseTimer.IsZero() {
 			lp.log.DEBUG.Printf("start phase %s timer", phaseScale1p)
 			lp.phaseTimer = lp.clock.Now()
@@ -1070,6 +1076,10 @@ func (lp *Loadpoint) pvScalePhases(availablePower, minCurrent, maxCurrent float6
 	if targetCurrent := powerToCurrent(availablePower, maxPhases); targetCurrent >= minCurrent && scalable {
 		lp.log.DEBUG.Printf("available power %.0fW > %.0fW min %dp threshold", availablePower, 3*Voltage*minCurrent, maxPhases)
 
+		if !lp.charging() { // scale immediately if not charging
+			lp.phaseTimer = elapsed
+		}
+
 		if lp.phaseTimer.IsZero() {
 			lp.log.DEBUG.Printf("start phase %s timer", phaseScale3p)
 			lp.phaseTimer = lp.clock.Now()
diff --git a/go.mod b/go.mod
index dd0ca806..a9c6c195 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,6 @@ require (
 	github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
 	github.com/containrrr/shoutrrr v0.8.0
 	github.com/coreos/go-oidc/v3 v3.6.0
-	github.com/deepmap/oapi-codegen v1.15.0
 	github.com/denisbrodbeck/machineid v1.0.1
 	github.com/dmarkham/enumer v1.5.8
 	github.com/dylanmei/iso8601 v0.1.0
@@ -79,7 +78,6 @@ require (
 	github.com/prometheus/common v0.44.0
 	github.com/robertkrimen/otto v0.2.1
 	github.com/samber/lo v1.38.1
-	github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
 	github.com/spf13/cast v1.5.1
 	github.com/spf13/cobra v1.7.0
@@ -106,32 +104,23 @@ require (
 )
 
 require (
-	github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
-	github.com/CloudyKit/jet/v6 v6.2.0 // indirect
-	github.com/Joker/jade v1.1.3 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.1 // indirect
-	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
 	github.com/ahmetb/go-linq/v3 v3.2.0 // indirect
-	github.com/andybalholm/brotli v1.0.5 // indirect
 	github.com/andybalholm/cascadia v1.3.2 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
-	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bitly/go-simplejson v0.5.0 // indirect
 	github.com/bytedance/sonic v1.10.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
-	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
-	github.com/chenzhuoyu/iasm v0.9.0 // indirect
 	github.com/chzyer/readline v1.5.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/deepmap/oapi-codegen v1.12.4 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/fatih/color v1.15.0 // indirect
 	github.com/felixge/httpsnoop v1.0.3 // indirect
-	github.com/flosch/pongo2/v4 v4.0.2 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
-	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/gin-gonic/gin v1.9.1 // indirect
 	github.com/glebarez/go-sqlite v1.21.2 // indirect
 	github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect
@@ -144,12 +133,8 @@ require (
 	github.com/gobwas/httphead v0.1.0 // indirect
 	github.com/gobwas/pool v0.2.1 // indirect
 	github.com/gobwas/ws v1.3.0 // indirect
-	github.com/goccy/go-json v0.10.2 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
-	github.com/golang/snappy v0.0.4 // indirect
-	github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
-	github.com/gorilla/css v1.0.0 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -157,34 +142,21 @@ require (
 	github.com/huandu/xstrings v1.4.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect
-	github.com/iris-contrib/schema v0.0.6 // indirect
 	github.com/itchyny/timefmt-go v0.1.5 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
-	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/kataras/blocks v0.0.7 // indirect
-	github.com/kataras/golog v0.1.9 // indirect
-	github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9 // indirect
-	github.com/kataras/pio v0.0.12 // indirect
-	github.com/kataras/sitemap v0.0.6 // indirect
-	github.com/kataras/tunnel v0.0.4 // indirect
 	github.com/klauspost/compress v1.16.7 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
 	github.com/kr/text v0.2.0 // indirect
-	github.com/labstack/echo/v4 v4.11.1 // indirect
-	github.com/labstack/gommon v0.4.0 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
-	github.com/mailgun/raymond/v2 v2.0.48 // indirect
-	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
 	github.com/mattn/go-runewidth v0.0.15 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
-	github.com/microcosm-cc/bluemonday v1.0.25 // indirect
 	github.com/miekg/dns v1.1.56 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
@@ -202,29 +174,19 @@ require (
 	github.com/rickb777/plural v1.4.1 // indirect
 	github.com/rivo/uniseg v0.4.4 // indirect
 	github.com/rogpeppe/go-internal v1.11.0 // indirect
-	github.com/russross/blackfriday/v2 v2.1.0 // indirect
-	github.com/schollz/closestmatch v2.1.0+incompatible // indirect
 	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/spf13/afero v1.9.5 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
-	github.com/tdewolff/minify/v2 v2.12.9 // indirect
-	github.com/tdewolff/parse/v2 v2.6.8 // indirect
 	github.com/teivah/onecontext v1.3.0 // indirect
-	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
-	github.com/ugorji/go/codec v1.2.11 // indirect
-	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	github.com/valyala/fasttemplate v1.2.2 // indirect
 	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
-	github.com/yosssi/ace v0.0.5 // indirect
 	gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a // indirect
 	golang.org/x/arch v0.5.0 // indirect
 	golang.org/x/crypto v0.13.0 // indirect
 	golang.org/x/mod v0.12.0 // indirect
 	golang.org/x/sys v0.12.0 // indirect
 	golang.org/x/term v0.12.0 // indirect
-	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.13.0 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
@@ -238,3 +200,5 @@ require (
 )
 
 replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20230705160100-23e1df2c01c3
+
+replace github.com/deepmap/oapi-codegen => github.com/deepmap/oapi-codegen v1.12.4
diff --git a/go.sum b/go.sum
index a02c950a..f2ce7fc0 100644
--- a/go.sum
+++ b/go.sum
@@ -43,14 +43,6 @@ github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi
 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
-github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
-github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
-github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
 github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -64,8 +56,6 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
 github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
 github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
 github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -73,8 +63,6 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
 github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZDE=
 github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/kLZh/cj9U=
-github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -86,8 +74,6 @@ github.com/andig/gosunspec v0.0.0-20211108155140-af2e73b86e71 h1:tnjVNZjuz+CK6fd
 github.com/andig/gosunspec v0.0.0-20211108155140-af2e73b86e71/go.mod h1:c6P6szcR+ROkqZruOR4f6qbDKFjZX6OitPpj+yJ/r8k=
 github.com/andig/mbserver v0.0.0-20230310211055-1d29cbb5820e h1:m/NTP3JWpR7M0ljLxiQU4fzR25jjhe1LDtxLMNcoNJQ=
 github.com/andig/mbserver v0.0.0-20230310211055-1d29cbb5820e/go.mod h1:4VtYzTm//oUipwvO3yh0g/udTE7pYJM+U/kyAuFDsgM=
-github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
-github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
 github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
 github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
@@ -108,8 +94,6 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
 github.com/aws/aws-sdk-go v1.45.11 h1:8qiSrA12+NRr+2MVpMApi3JxtiFFjDVU1NeWe+80bYg=
 github.com/aws/aws-sdk-go v1.45.11/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
-github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw=
 github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
 github.com/basvdlei/gotsmart v0.0.3 h1:7hrI6btBc8dmFzzHRDkr9Xl87PvrrOT43DzbsTFqMk8=
@@ -182,8 +166,8 @@ github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/deepmap/oapi-codegen v1.15.0 h1:SQqViaeb4k2vMul8gx12oDOIadEtoRqTdLkxjzqtQ90=
-github.com/deepmap/oapi-codegen v1.15.0/go.mod h1:a6KoHV7lMRwsPoEg2C6NDHiXYV3EQfiFocOlJ8dgJQE=
+github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s=
+github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas=
 github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
 github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -223,8 +207,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
 github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
-github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
@@ -291,8 +273,6 @@ github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGi
 github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
 github.com/goburrow/serial v0.1.0 h1:v2T1SQa/dlUqQiYIT8+Cu7YolfqAi3K96UmhwYyuSrA=
 github.com/goburrow/serial v0.1.0/go.mod h1:sAiqG0nRVswsm1C97xsttiYCzSLBmUZ/VSlVLZJ8haA=
-github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
 github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
 github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
@@ -349,10 +329,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd h1:laCEzrtkKEkT2424vMTGl6N1m0xN8kq371hksD5Be+8=
-github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -402,8 +378,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
 github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
 github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
 github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
 github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -466,8 +440,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
 github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
-github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
-github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
@@ -476,10 +448,6 @@ github.com/influxdata/influxdb-client-go/v2 v2.12.3/go.mod h1:IrrLUbCjjfkmRuaCiG
 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU=
 github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
-github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
-github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
-github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
-github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
 github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
 github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
 github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
@@ -504,8 +472,6 @@ github.com/joeshaw/carwings v0.0.0-20230425210048-195f7e10e966/go.mod h1:tB0Olpi
 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 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=
 github.com/jpfielding/gowirelog v0.0.0-20200123170752-df8f8dccb721/go.mod h1:R8b6Hefiy6MSxbJ8dbF9Gkaa/LwFh9meFV0i9hkR5i8=
@@ -525,18 +491,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
 github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4=
-github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
-github.com/kataras/golog v0.1.9 h1:vLvSDpP7kihFGKFAvBSofYo7qZNULYSHOH2D7rPTKJk=
-github.com/kataras/golog v0.1.9/go.mod h1:jlpk/bOaYCyqDqH18pgDHdaJab72yBE6i0O3s30hpWY=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9 h1:Vx8kDVhO2qepK8w44lBtp+RzN3ld743i+LYPzODJSpQ=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9/go.mod h1:ldkoR3iXABBeqlTibQ3MYaviA1oSlPvim6f55biwBh4=
-github.com/kataras/pio v0.0.12 h1:o52SfVYauS3J5X08fNjlGS5arXHjW/ItLkyLcKjoH6w=
-github.com/kataras/pio v0.0.12/go.mod h1:ODK/8XBhhQ5WqrAhKy+9lTPS7sBf6O3KcLhc9klfRcY=
-github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
-github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
-github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
-github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -563,10 +517,6 @@ 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.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
-github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
-github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
-github.com/labstack/gommon v0.4.0/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=
 github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
@@ -584,22 +534,16 @@ github.com/mabunixda/wattpilot v1.6.2 h1:xZE/elFntUJgaWTK2V7CJVQRcE+WvkT8g6dCk/o
 github.com/mabunixda/wattpilot v1.6.2/go.mod h1:2tcdLRoqycO6bWYAjZMP9g1giMgw4t2MnbN3VxaCN1Q=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
-github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
-github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
-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.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
 github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
@@ -615,8 +559,6 @@ github.com/mergermarket/go-pkcs7 v0.0.0-20170926155232-153b18ea13c9/go.mod h1:GH
 github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
-github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
 github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
@@ -629,8 +571,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
-github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -775,31 +715,21 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
 github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
 github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
 github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
-github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
-github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
-github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
 github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=
-github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/simonvetter/modbus v1.6.0 h1:RDHJevtc7LDIVoHAbhDun8fy+QwnGe+ZU+sLm9ZZzjc=
 github.com/simonvetter/modbus v1.6.0/go.mod h1:hh90ZaTaPLcK2REj6/fpTbiV0J6S7GWmd8q+GVRObPw=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
@@ -852,12 +782,6 @@ github.com/suapapa/go_eddystone v1.3.1/go.mod h1:bXC11TfJOS+3g3q/Uzd7FKd5g62STQE
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/tdewolff/minify/v2 v2.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA=
-github.com/tdewolff/minify/v2 v2.12.9/go.mod h1:qOqdlDfL+7v0/fyymB+OP497nIxJYSvX4MQWA8OoiXU=
-github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvFMA=
-github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
-github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
-github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
 github.com/teivah/onecontext v1.3.0 h1:tbikMhAlo6VhAuEGCvhc8HlTnpX4xTNPTOseWuhO1J0=
 github.com/teivah/onecontext v1.3.0/go.mod h1:hoW1nmdPVK/0jrvGtcx8sCKYs2PiS4z0zzfdeuEVyb0=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -867,17 +791,13 @@ github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDH
 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
 github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 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/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
-github.com/valyala/fasttemplate v1.2.2/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=
 github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
@@ -886,27 +806,12 @@ github.com/volkszaehler/mbmd v0.0.0-20230819073623-ab54b0355354 h1:6rhritdmrLjG0
 github.com/volkszaehler/mbmd v0.0.0-20230819073623-ab54b0355354/go.mod h1:kUsZrJ4IyhmhDERIxJDysTuO0wtZFavwL8AInnCZ0Oo=
 github.com/writeas/go-strip-markdown/v2 v2.1.1 h1:hAxUM21Uhznf/FnbVGiJciqzska6iLei22Ijc3q2e28=
 github.com/writeas/go-strip-markdown/v2 v2.1.1/go.mod h1:UvvgPJgn1vvN8nWuE5e7v/+qmDu3BSVnKAB6Gl7hFzA=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
-github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
-github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
-github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 gitlab.com/bboehmke/sunny v0.15.1-0.20211022160056-2fba1c86ade6 h1:73pM5aQqFkQfmXyGf3+xeWWg98J03xtDIkA5TE37ERU=
 gitlab.com/bboehmke/sunny v0.15.1-0.20211022160056-2fba1c86ade6/go.mod h1:F5AIuL7kYteSJFR5E+YEocxIdpyCXmtDciFmMQVjP88=
@@ -975,9 +880,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI=
 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -989,7 +893,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
@@ -1005,7 +908,6 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -1039,7 +941,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
@@ -1097,7 +998,6 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1138,10 +1038,6 @@ golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1182,8 +1078,6 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1242,7 +1136,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
@@ -1362,7 +1255,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
@@ -1393,7 +1285,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
@@ -1414,8 +1305,6 @@ modernc.org/memory v1.7.1 h1:9J+2/GKTlV503mk3yv8QJ6oEpRCUrRy0ad8TXEPoV8M=
 modernc.org/memory v1.7.1/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
 modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
 modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
-moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
-moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
 nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
diff --git a/meter/tibber/client.go b/meter/tibber/client.go
index b5d464fd..ebd80168 100644
--- a/meter/tibber/client.go
+++ b/meter/tibber/client.go
@@ -7,7 +7,7 @@ import (
 
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/request"
-	"github.com/shurcooL/graphql"
+	"github.com/hasura/go-graphql-client"
 	"golang.org/x/oauth2"
 )
 
diff --git a/provider/mqtt/client.go b/provider/mqtt/client.go
index f0042a83..658a3490 100644
--- a/provider/mqtt/client.go
+++ b/provider/mqtt/client.go
@@ -6,6 +6,7 @@ import (
 	"math/rand"
 	"strings"
 	"sync"
+	"sync/atomic"
 
 	paho "github.com/eclipse/paho.mqtt.golang"
 	"github.com/evcc-io/evcc/api"
@@ -38,6 +39,7 @@ type Client struct {
 	Client   paho.Client
 	broker   string
 	Qos      byte
+	inflight uint32
 	listener map[string][]func(string)
 }
 
@@ -168,6 +170,14 @@ func (m *Client) listen(topic string) {
 
 // WaitForToken synchronously waits until token operation completed
 func (m *Client) WaitForToken(action, topic string, token paho.Token) {
+	if inflight := atomic.LoadUint32(&m.inflight); inflight > 64 {
+		return
+	}
+
+	// track inflight token waits
+	atomic.AddUint32(&m.inflight, 1)
+	defer atomic.AddUint32(&m.inflight, ^uint32(0))
+
 	err := api.ErrTimeout
 	if token.WaitTimeout(request.Timeout) {
 		err = token.Error()
diff --git a/tariff/tibber.go b/tariff/tibber.go
index a106272f..e54c4f3a 100644
--- a/tariff/tibber.go
+++ b/tariff/tibber.go
@@ -12,7 +12,7 @@ import (
 	"github.com/evcc-io/evcc/meter/tibber"
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/request"
-	"github.com/shurcooL/graphql"
+	"github.com/hasura/go-graphql-client"
 )
 
 type Tibber struct {
diff --git a/templates/definition/charger/bender.yaml b/templates/definition/charger/bender.yaml
index 22c51fb9..69586359 100644
--- a/templates/definition/charger/bender.yaml
+++ b/templates/definition/charger/bender.yaml
@@ -38,8 +38,6 @@ requirements:
   evcc: ["sponsorship"]
 params:
   - name: host
-    required: true
-    example: 192.0.2.2
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/charger/daheimladen-mb.yaml b/templates/definition/charger/daheimladen-mb.yaml
index 6502c624..bbda1aee 100644
--- a/templates/definition/charger/daheimladen-mb.yaml
+++ b/templates/definition/charger/daheimladen-mb.yaml
@@ -9,8 +9,6 @@ requirements:
     en: Wallbox must be operated with a recent firmware including Modbus support. Furthermore, “Nachladen” (Smart) or “RSDA” (Touch) must be activated in settings.
 params:
   - name: host
-    required: true
-    example: 192.0.2.2
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/charger/easee.yaml b/templates/definition/charger/easee.yaml
index d6dcdb6a..923b5fae 100644
--- a/templates/definition/charger/easee.yaml
+++ b/templates/definition/charger/easee.yaml
@@ -14,7 +14,6 @@ params:
       en: Email address
   - name: password
     required: true
-    mask: true
     help:
       de: wie Login für Easee App oder Web Portal (https://easee.cloud)
       en: same as Easee app or the web portal (https://easee.cloud)
diff --git a/templates/definition/charger/etrel-duo.yaml b/templates/definition/charger/etrel-duo.yaml
index 93c2ad40..bfbc8034 100644
--- a/templates/definition/charger/etrel-duo.yaml
+++ b/templates/definition/charger/etrel-duo.yaml
@@ -12,7 +12,6 @@ requirements:
 params:
   - name: connector
   - name: host
-    required: true
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/charger/etrel.yaml b/templates/definition/charger/etrel.yaml
index 6efaa385..56201b9d 100644
--- a/templates/definition/charger/etrel.yaml
+++ b/templates/definition/charger/etrel.yaml
@@ -14,7 +14,6 @@ requirements:
     en: The charger must be switched to "Power" charging mode.
 params:
   - name: host
-    required: true
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/charger/fritzdect.yaml b/templates/definition/charger/fritzdect.yaml
index f7e31522..7e7e842f 100644
--- a/templates/definition/charger/fritzdect.yaml
+++ b/templates/definition/charger/fritzdect.yaml
@@ -11,7 +11,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: ain
     required: true
   - preset: switchsocket
diff --git a/templates/definition/charger/mennekes.yaml b/templates/definition/charger/mennekes.yaml
new file mode 100644
index 00000000..07053f75
--- /dev/null
+++ b/templates/definition/charger/mennekes.yaml
@@ -0,0 +1,23 @@
+template: mennekes
+products:
+  - brand: Mennekes
+    description:
+      generic: Amtron Compact 2.0s
+  - brand: Mennekes
+    description:
+      generic: Amtron Start 2.0s
+capabilities: ["1p3p", "mA"]
+requirements:
+  description:
+    de: Die Wallbox muss mit Hilfe der DIP-Schalter auf der Hauptplatine als Satellit konfiguriert werden.
+    en: The charger needs to be configured as Satellite with help of the DIP-Switches on the baseboard.
+  evcc: ["sponsorship"]
+params:
+  - name: modbus
+    choice: ["rs485"]
+    baudrate: 57600
+    comset: 8N2
+    id: 50
+render: |
+  type: mennekes
+  {{- include "modbus" . }}
diff --git a/templates/definition/charger/nrgkick-connect.yaml b/templates/definition/charger/nrgkick-connect.yaml
index 72adaae2..4565d6ac 100644
--- a/templates/definition/charger/nrgkick-connect.yaml
+++ b/templates/definition/charger/nrgkick-connect.yaml
@@ -9,7 +9,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
 render: |
   type: nrgkick-connect
   uri: http://{{ .host }}
diff --git a/templates/definition/charger/openevse.yaml b/templates/definition/charger/openevse.yaml
index 13bce293..1bf80f82 100644
--- a/templates/definition/charger/openevse.yaml
+++ b/templates/definition/charger/openevse.yaml
@@ -7,7 +7,6 @@ requirements:
     de: Benötigt mindestens Firmware 7.0 oder neuer.
 params:
   - name: host
-    required: true
   - name: user
     required: false
   - name: password
diff --git a/templates/definition/charger/smaevcharger.yaml b/templates/definition/charger/smaevcharger.yaml
index 70a411b2..4e0a196f 100644
--- a/templates/definition/charger/smaevcharger.yaml
+++ b/templates/definition/charger/smaevcharger.yaml
@@ -11,12 +11,10 @@ requirements:
     en: The charger must be switched to "Fast" charging mode and the user must have "Administrator" rights.
 params:
   - name: host
-    required: true
   - name: user
     required: true
   - name: password
     required: true
-    mask: true
 render: |
   type: smaevcharger
   uri: http://{{ .host }}
diff --git a/templates/definition/charger/tapo.yaml b/templates/definition/charger/tapo.yaml
index 8fb60ecd..23d29cc4 100644
--- a/templates/definition/charger/tapo.yaml
+++ b/templates/definition/charger/tapo.yaml
@@ -10,7 +10,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - preset: switchsocket
 render: |
   type: tapo
diff --git a/templates/definition/charger/victron.yaml b/templates/definition/charger/victron.yaml
new file mode 100644
index 00000000..1bd52401
--- /dev/null
+++ b/templates/definition/charger/victron.yaml
@@ -0,0 +1,17 @@
+template: victron
+products:
+  - brand: Victron
+    description:
+      generic: EV charging station
+requirements:
+  evcc: ["sponsorship"]
+  description:
+    en: Charger has to be in manual mode and Modbus has to be configured for ID 100.
+    de: Wallbox muss sich im Modus "Manual" befinden und Modbus ID 100 konfiguriert sein.
+params:
+  - name: modbus
+    choice: ["tcpip"]
+    id: 100
+render: |
+  type: victron
+  {{- include "modbus" . }}
diff --git a/templates/definition/charger/webasto-next.yaml b/templates/definition/charger/webasto-next.yaml
index 265fc808..fe96bbf4 100644
--- a/templates/definition/charger/webasto-next.yaml
+++ b/templates/definition/charger/webasto-next.yaml
@@ -11,8 +11,6 @@ requirements:
   evcc: ["sponsorship"]
 params:
   - name: host
-    required: true
-    example: 192.0.2.2
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/meter/discovergy.yaml b/templates/definition/meter/discovergy.yaml
index dd60078c..0de6a7f8 100644
--- a/templates/definition/meter/discovergy.yaml
+++ b/templates/definition/meter/discovergy.yaml
@@ -9,7 +9,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: meter
     required: true
     example: 1ESY1161229886
diff --git a/templates/definition/meter/enphase.yaml b/templates/definition/meter/enphase.yaml
index 0367d143..2b94cea1 100644
--- a/templates/definition/meter/enphase.yaml
+++ b/templates/definition/meter/enphase.yaml
@@ -11,7 +11,6 @@ params:
   - name: usage
     choice: ["grid", "pv", "battery"]
   - name: host
-    required: true
   - name: token
     help:
       en: "Required if Envoy Firmware D7.x.xxx. Token is valid for one year. Instructions for obtaining a token via web UI: https://enphase.com/download/accessing-iq-gateway-local-apis-or-local-ui-token-based-authentication"
diff --git a/templates/definition/meter/fritzdect.yaml b/templates/definition/meter/fritzdect.yaml
index 730d721b..3362ff78 100644
--- a/templates/definition/meter/fritzdect.yaml
+++ b/templates/definition/meter/fritzdect.yaml
@@ -13,7 +13,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: ain
     required: true
 render: |
diff --git a/templates/definition/meter/homewizard.yaml b/templates/definition/meter/homewizard.yaml
index 6a292160..6afc3bd1 100644
--- a/templates/definition/meter/homewizard.yaml
+++ b/templates/definition/meter/homewizard.yaml
@@ -7,7 +7,6 @@ params:
   - name: usage
     choice: ["grid", "pv"]
   - name: host
-    required: true
 render: |
   type: homewizard
   uri: http://{{ .host }}
diff --git a/templates/definition/meter/hoymiles-opendtu.yaml b/templates/definition/meter/hoymiles-opendtu.yaml
index cafe8afc..86f7ec1c 100644
--- a/templates/definition/meter/hoymiles-opendtu.yaml
+++ b/templates/definition/meter/hoymiles-opendtu.yaml
@@ -7,7 +7,6 @@ params:
   - name: usage
     choice: ["pv"]
   - name: host
-    required: true
 render: |
   type: custom
   power:
diff --git a/templates/definition/meter/huawei-smartlogger.yaml b/templates/definition/meter/huawei-smartlogger.yaml
index a9c2d7a8..29ee9289 100644
--- a/templates/definition/meter/huawei-smartlogger.yaml
+++ b/templates/definition/meter/huawei-smartlogger.yaml
@@ -7,8 +7,6 @@ params:
   - name: usage
     choice: ["pv"]
   - name: host
-    required: true
-    example: 192.0.2.2
   - name: port
     default: 502
 render: |
diff --git a/templates/definition/meter/lg-ess-home-8-10.yaml b/templates/definition/meter/lg-ess-home-8-10.yaml
index f07a59d4..2ecd69c6 100644
--- a/templates/definition/meter/lg-ess-home-8-10.yaml
+++ b/templates/definition/meter/lg-ess-home-8-10.yaml
@@ -10,10 +10,12 @@ params:
   - name: host
   - name: password
     help:
-      en: |
-        User password, see https://github.com/Morluktom/ioBroker.lg-ess-home/tree/master#getting-the-password.Alteratively, use registration id for admin login.
-      de: |
-        Benutzerpasswort, siehe https://github.com/Morluktom/ioBroker.lg-ess-home/tree/master#getting-the-password.Alterativ kann die Registriernummer für Administratorlogin verwendet werden.
+      en: >
+        User password, see https://github.com/Morluktom/ioBroker.lg-ess-home/tree/master#getting-the-password.
+        Alteratively, use registration id for admin login.
+      de: >
+        Benutzerpasswort, siehe https://github.com/Morluktom/ioBroker.lg-ess-home/tree/master#getting-the-password.
+        Alterativ kann die Registriernummer für Administratorlogin verwendet werden.
   - name: registration
     advanced: true
     example: "DE200..."
diff --git a/templates/definition/meter/p1monitor.yaml b/templates/definition/meter/p1monitor.yaml
new file mode 100644
index 00000000..1a18378f
--- /dev/null
+++ b/templates/definition/meter/p1monitor.yaml
@@ -0,0 +1,60 @@
+template: p1monitor
+products:
+  - brand: P1Monitor
+    description:
+      generic: P1 Monitor
+params:
+  - name: usage
+    choice: ["grid"]
+  - name: host
+render: |
+  {{- define "uri" -}}
+  http://{{ .host }}/api/v1
+  {{- end }}
+  type: custom
+  power:  
+    source: calc
+    add:
+    - source: http
+      uri: {{ include "uri" . }}/status/74
+      jq: .[0].[1]
+      scale: 1000
+    - source: http
+      uri: {{ include "uri" . }}/status/75
+      jq: .[0].[1]
+      scale: 1000
+    - source: http
+      uri: {{ include "uri" . }}/status/76
+      jq: .[0].[1]
+      scale: 1000
+    - source: http
+      uri: {{ include "uri" . }}/status/77
+      jq: .[0].[1]
+      scale: -1000
+    - source: http
+      uri: {{ include "uri" . }}/status/78
+      jq: .[0].[1]
+      scale: -1000
+    - source: http
+      uri: {{ include "uri" . }}/status/79
+      jq: .[0].[1]
+      scale: -1000
+  energy:
+    source: calc
+    add:
+    - source: http
+      uri: {{ include "uri" . }}/smartmeter?limit=1
+      jq: .[0].[3]
+    - source: http
+      uri: {{ include "uri" . }}/smartmeter?limit=1
+      jq: .[0].[4]
+  currents:
+  - source: http
+    uri: {{ include "uri" . }}/status/100
+    jq: .[0].[1]
+  - source: http
+    uri: {{ include "uri" . }}/status/101
+    jq: .[0].[1]
+  - source: http
+    uri: {{ include "uri" . }}/status/102
+    jq: .[0].[1]
diff --git a/templates/definition/meter/powerfox-poweropti.yaml b/templates/definition/meter/powerfox-poweropti.yaml
index 6ee37427..3daab90e 100644
--- a/templates/definition/meter/powerfox-poweropti.yaml
+++ b/templates/definition/meter/powerfox-poweropti.yaml
@@ -10,7 +10,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: id
     default: main
     required: true
diff --git a/templates/definition/meter/shelly-1pm.yaml b/templates/definition/meter/shelly-1pm.yaml
index 97b919d0..3dd14314 100644
--- a/templates/definition/meter/shelly-1pm.yaml
+++ b/templates/definition/meter/shelly-1pm.yaml
@@ -8,7 +8,6 @@ params:
   - name: usage
     choice: ["pv", "charge"]
   - name: host
-    default: 192.0.2.2
   - name: user
   - name: password
   - name: channel
diff --git a/templates/definition/meter/shelly-pro-3em.yaml b/templates/definition/meter/shelly-pro-3em.yaml
index 15b493bb..30d3a55a 100644
--- a/templates/definition/meter/shelly-pro-3em.yaml
+++ b/templates/definition/meter/shelly-pro-3em.yaml
@@ -7,7 +7,6 @@ params:
   - name: usage
     choice: ["grid", "pv", "charge"]
   - name: host
-    default: 192.0.2.2
   - name: user
   - name: password
 render: |
diff --git a/templates/definition/meter/slimmelezer.yaml b/templates/definition/meter/slimmelezer.yaml
index 07df929d..f473addf 100644
--- a/templates/definition/meter/slimmelezer.yaml
+++ b/templates/definition/meter/slimmelezer.yaml
@@ -10,7 +10,6 @@ params:
   - name: usage
     choice: ["grid"]
   - name: host
-    required: true
 render: |
   type: custom
   power:
diff --git a/templates/definition/meter/tapo.yaml b/templates/definition/meter/tapo.yaml
index 1e2e07c1..fe841fd5 100644
--- a/templates/definition/meter/tapo.yaml
+++ b/templates/definition/meter/tapo.yaml
@@ -12,7 +12,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
 render: |
   type: tapo
   uri: http://{{ .host }}
diff --git a/templates/definition/meter/tasmota.yaml b/templates/definition/meter/tasmota.yaml
index cb66c0f8..65d888b1 100644
--- a/templates/definition/meter/tasmota.yaml
+++ b/templates/definition/meter/tasmota.yaml
@@ -7,7 +7,6 @@ params:
   - name: usage
     choice: ["grid", "pv", "battery"]
   - name: host
-    default: 192.0.2.2
   - name: user
     required: false
     help:
diff --git a/templates/definition/meter/tesla-powerwall.yaml b/templates/definition/meter/tesla-powerwall.yaml
index 99134311..ee9497c3 100644
--- a/templates/definition/meter/tesla-powerwall.yaml
+++ b/templates/definition/meter/tesla-powerwall.yaml
@@ -10,7 +10,6 @@ params:
   - name: host
   - name: password
     required: true
-    mask: true
     help:
       en: Password of the user "customer"
       de: Passwort des Benutzers "Kunde"
diff --git a/templates/definition/meter/tplink.yaml b/templates/definition/meter/tplink.yaml
index d2240488..f9ad71d4 100644
--- a/templates/definition/meter/tplink.yaml
+++ b/templates/definition/meter/tplink.yaml
@@ -8,7 +8,6 @@ params:
   - name: usage
     choice: ["pv"]
   - name: host
-    default: 192.0.2.2
 render: |
   type: tplink
   uri: {{ .host }}
diff --git a/templates/definition/meter/youless.yaml b/templates/definition/meter/youless.yaml
index 22f39cd1..de8cc30a 100644
--- a/templates/definition/meter/youless.yaml
+++ b/templates/definition/meter/youless.yaml
@@ -13,7 +13,6 @@ params:
   - name: usage
     choice: ["grid", "pv"]
   - name: host
-    required: true
 render: |
   type: custom
   {{- if eq .usage "grid" }}
diff --git a/templates/definition/vehicle/niu-e-scooter.yaml b/templates/definition/vehicle/niu-e-scooter.yaml
index cb54ce54..b7312d43 100644
--- a/templates/definition/vehicle/niu-e-scooter.yaml
+++ b/templates/definition/vehicle/niu-e-scooter.yaml
@@ -12,7 +12,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: serial
     description:
       de: Scooter Seriennummer, wie in der NIU app angegeben
diff --git a/templates/definition/vehicle/ovms.yaml b/templates/definition/vehicle/ovms.yaml
index 97e86636..98b6b9d5 100644
--- a/templates/definition/vehicle/ovms.yaml
+++ b/templates/definition/vehicle/ovms.yaml
@@ -16,7 +16,6 @@ params:
     required: true
   - name: password
     required: true
-    mask: true
   - name: vehicleid
     required: true
   - name: capacity
diff --git a/templates/evcc.io/brands.json b/templates/evcc.io/brands.json
index b9ff7a24..f7148374 100644
--- a/templates/evcc.io/brands.json
+++ b/templates/evcc.io/brands.json
@@ -61,6 +61,7 @@
   "TinkerForge",
   "Ubitricity",
   "Vestel",
+  "Victron",
   "Volkswagen",
   "Wallbe",
   "wallbox",
@@ -109,6 +110,7 @@
   "myStrom",
   "OpenEMS",
   "Orno",
+  "P1Monitor",
   "Powerfox",
   "Qcells",
   "RCT",
diff --git a/util/templates/documentation.go b/util/templates/documentation.go
index 77b46f4d..3754bb14 100644
--- a/util/templates/documentation.go
+++ b/util/templates/documentation.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	_ "embed"
 	"fmt"
+	"strings"
 	"text/template"
 
 	"github.com/Masterminds/sprig/v3"
@@ -108,6 +109,6 @@ func (t *Template) RenderDocumentation(product Product, lang string) ([]byte, er
 
 func localize(lang string) func(TextLanguage) string {
 	return func(s TextLanguage) string {
-		return s.String(lang)
+		return strings.TrimSpace(s.String(lang))
 	}
 }
diff --git a/vehicle/audi/etron/api.go b/vehicle/audi/etron/api.go
index 0b2dc072..dbdacadb 100644
--- a/vehicle/audi/etron/api.go
+++ b/vehicle/audi/etron/api.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/request"
-	"github.com/shurcooL/graphql"
+	"github.com/hasura/go-graphql-client"
 	"golang.org/x/oauth2"
 )
 


Test patch:
diff --git a/core/loadpoint_phases_test.go b/core/loadpoint_phases_test.go
index 857dce20..19a83420 100644
--- a/core/loadpoint_phases_test.go
+++ b/core/loadpoint_phases_test.go
@@ -192,6 +192,7 @@ func TestPvScalePhases(t *testing.T) {
 			vehicle:          vehicle,
 			ConfiguredPhases: 0, // allow switching
 			phases:           tc.physical,
+			status:           api.StatusC,
 		}
 
 		if phaseCharger != nil {
@@ -326,6 +327,15 @@ func TestPvScalePhasesTimer(t *testing.T) {
 			lp.phaseTimer = lp.clock.Now().Add(-dt)
 		}},
 
+		// switch down from 3p/0p while not yet charging
+		{"3/0->1, not enough power, not charging", 3, 0, 0, 1, true, func(lp *Loadpoint) {
+			lp.status = api.StatusB
+		}},
+		// switch up from 1p/0p while not yet charging
+		{"1/0->3, enough power, not charging", 1, 0, 3 * Voltage * minA, 3, true, func(lp *Loadpoint) {
+			lp.status = api.StatusB
+		}},
+
 		// error states from 1p/3p misconfig - no correction for time being (stay at 1p)
 		{"1/3->1, enough power", 1, 3, 1 * Voltage * maxA, 1, false, nil},
 		{"1/3->1, kickoff, correct phase setting", 1, 3, 1 * Voltage * maxA, 1, false, func(lp *Loadpoint) {
@@ -352,6 +362,7 @@ func TestPvScalePhasesTimer(t *testing.T) {
 			MaxCurrent:     maxA,
 			phases:         tc.phases,
 			measuredPhases: tc.measuredPhases,
+			status:         api.StatusC,
 			Enable: ThresholdConfig{
 				Delay: dt,
 			},