diff --git a/Makefile b/Makefile index e041fa560..ff1e3177d 100644 --- a/Makefile +++ b/Makefile @@ -79,9 +79,6 @@ snapshot:: release:: goreleaser --clean -openapi:: - cd server/mcp && go run github.com/evcc-io/evcc/server/mcp/openapi https://raw.githubusercontent.com/evcc-io/docs/refs/heads/main/static/rest-api.yaml - docker:: @echo Version: $(VERSION) $(SHA) $(BUILD_DATE) docker buildx build --platform $(PLATFORM) --tag $(DOCKER_IMAGE):$(DOCKER_TAG) --push . diff --git a/assets/js/components/ChargingPlans/PlansSettings.vue b/assets/js/components/ChargingPlans/PlansSettings.vue index ebfdcec67..c50e102a9 100644 --- a/assets/js/components/ChargingPlans/PlansSettings.vue +++ b/assets/js/components/ChargingPlans/PlansSettings.vue @@ -232,7 +232,7 @@ export default defineComponent({ async updateActivePlan(): Promise { try { const res = await this.apiFetchPlan(`loadpoints/${this.id}/plan`); - this.plan = res?.data.result ?? ({} as PlanWrapper); + this.plan = res?.data ?? ({} as PlanWrapper); this.nextPlanId = this.plan.planId; } catch (e) { console.error(e); @@ -271,7 +271,7 @@ export default defineComponent({ params, })) as PlanResponse; if (res.status === 404) { - return { data: { result: {} as PlanWrapper } } as PlanResponse; + return { data: {} } as PlanResponse; } return res; } catch (e) { @@ -322,7 +322,7 @@ export default defineComponent({ precondition, }); } - this.plan = planRes?.data.result ?? ({} as PlanWrapper); + this.plan = planRes?.data ?? ({} as PlanWrapper); } catch (e) { console.error(e); } diff --git a/assets/js/components/ChargingPlans/types.d.ts b/assets/js/components/ChargingPlans/types.d.ts index b12b806ae..c93f60623 100644 --- a/assets/js/components/ChargingPlans/types.d.ts +++ b/assets/js/components/ChargingPlans/types.d.ts @@ -19,7 +19,7 @@ export interface PlanWrapper { export interface PlanResponse { status: number; - data: { result: PlanWrapper }; + data: PlanWrapper; } export type StaticPlan = StaticSocPlan | StaticEnergyPlan; diff --git a/assets/js/components/Config/DeviceModal/index.ts b/assets/js/components/Config/DeviceModal/index.ts index 29a3de2ff..eb8650036 100644 --- a/assets/js/components/Config/DeviceModal/index.ts +++ b/assets/js/components/Config/DeviceModal/index.ts @@ -103,12 +103,12 @@ export function createDeviceUtils(deviceType: DeviceType) { async function load(id: number) { const response = await api.get(`config/devices/${deviceType}/${id}`); - return response.data.result; + return response.data; } async function create(data: any) { const response = await api.post(`config/devices/${deviceType}`, data); - return response.data.result; + return response.data; } async function loadProducts(lang?: string, usage?: string) { @@ -117,7 +117,7 @@ export function createDeviceUtils(deviceType: DeviceType) { params["usage"] = usage; } const response = await api.get(`config/products/${deviceType}`, { params }); - return response.data.result; + return response.data; } async function loadTemplate(templateName: string, lang?: string) { @@ -130,7 +130,7 @@ export function createDeviceUtils(deviceType: DeviceType) { }, }; const response = await api.get(`config/templates/${deviceType}`, opts); - return response.data.result; + return response.data; } return { diff --git a/assets/js/components/Config/GeneralConfig.vue b/assets/js/components/Config/GeneralConfig.vue index 4da3ce528..78657518d 100644 --- a/assets/js/components/Config/GeneralConfig.vue +++ b/assets/js/components/Config/GeneralConfig.vue @@ -125,7 +125,7 @@ export default { validateStatus: (code) => [200, 404].includes(code), }); if (res.status === 200) { - this.title = res.data.result.title; + this.title = res.data.title; } else { console.log("TODO: implement site endpoint in config error mode"); } diff --git a/assets/js/components/Config/LoadpointModal.vue b/assets/js/components/Config/LoadpointModal.vue index d873d0f3e..2ec5b6819 100644 --- a/assets/js/components/Config/LoadpointModal.vue +++ b/assets/js/components/Config/LoadpointModal.vue @@ -795,7 +795,7 @@ export default { async loadConfiguration() { try { const res = await api.get(`config/loadpoints/${this.id}`); - this.values = deepClone(res.data.result); + this.values = deepClone(res.data); this.updateChargerPower(); this.updateSolarMode(); this.updatePhases(); diff --git a/assets/js/components/Config/YamlModal.vue b/assets/js/components/Config/YamlModal.vue index 8f7c5172c..3f654dee5 100644 --- a/assets/js/components/Config/YamlModal.vue +++ b/assets/js/components/Config/YamlModal.vue @@ -100,8 +100,8 @@ export default { async load() { try { const { data } = await api.get(this.endpoint); - this.serverYaml = data.result; - this.yaml = data.result || this.defaultYaml; + this.serverYaml = data; + this.yaml = data || this.defaultYaml; } catch (e) { console.error(e); } diff --git a/assets/js/components/Config/mixins/test.js b/assets/js/components/Config/mixins/test.js index 9b1990e61..7a444d221 100644 --- a/assets/js/components/Config/mixins/test.js +++ b/assets/js/components/Config/mixins/test.js @@ -38,7 +38,7 @@ export default { this.testState = TEST_RUNNING; try { const res = await testApi(); - for (const [key, { error }] of Object.entries(res.data.result)) { + for (const [key, { error }] of Object.entries(res.data)) { if (error) { this.testState = TEST_FAILED; this.testResult = null; @@ -46,7 +46,7 @@ export default { return false; } } - this.testResult = res.data.result; + this.testResult = res.data; this.testError = null; this.testState = TEST_SUCCESS; return true; diff --git a/assets/js/components/Config/utils/test.ts b/assets/js/components/Config/utils/test.ts index 21e850426..888f4f7f3 100644 --- a/assets/js/components/Config/utils/test.ts +++ b/assets/js/components/Config/utils/test.ts @@ -33,7 +33,7 @@ export const performTest = async ( state.errorLine = null; try { const res = await api(); - for (const [key, value] of Object.entries(res.data.result)) { + for (const [key, value] of Object.entries(res.data)) { const { error } = value as { error?: string }; if (error) { state.isError = true; @@ -42,7 +42,7 @@ export const performTest = async ( } } state.isSuccess = true; - state.result = res.data.result; + state.result = res.data; return true; } catch (e: any) { state.isError = true; diff --git a/assets/js/components/Savings/Savings.vue b/assets/js/components/Savings/Savings.vue index 1a87b4d02..bc5c91023 100644 --- a/assets/js/components/Savings/Savings.vue +++ b/assets/js/components/Savings/Savings.vue @@ -331,7 +331,7 @@ export default defineComponent({ async updateReferenceGrid() { try { const res = await api.get(`tariff/grid`, allowClientError); - const { rates } = res.data.result as { rates: Rate[] }; + const { rates } = res.data as { rates: Rate[] }; this.referenceGrid = rates.reduce((acc, slot) => { return acc + slot.value; diff --git a/assets/js/views/Config.vue b/assets/js/views/Config.vue index 20e67a63d..c96be4274 100644 --- a/assets/js/views/Config.vue +++ b/assets/js/views/Config.vue @@ -646,37 +646,37 @@ export default { }, async loadDirty() { const response = await api.get("/config/dirty"); - if (response.data?.result) { + if (response.data) { restart.restartNeeded = true; } }, async loadVehicles() { const response = await api.get("/config/devices/vehicle"); - this.vehicles = response.data?.result || []; + this.vehicles = response.data || []; }, async loadChargers() { const response = await api.get("/config/devices/charger"); - this.chargers = response.data?.result || []; + this.chargers = response.data || []; }, async loadMeters() { const response = await api.get("/config/devices/meter"); - this.meters = response.data?.result || []; + this.meters = response.data || []; }, async loadCircuits() { const response = await api.get("/config/devices/circuit"); - this.circuits = response.data?.result || []; + this.circuits = response.data || []; }, async loadSite() { const response = await api.get("/config/site", { validateStatus: (status) => status < 500, }); if (response.status === 200) { - this.site = response.data?.result; + this.site = response.data; } }, async loadLoadpoints() { const response = await api.get("/config/loadpoints"); - this.loadpoints = response.data?.result || []; + this.loadpoints = response.data || []; }, getMetersByNames(names) { if (!names || !this.meters) { @@ -865,7 +865,7 @@ export default { try { const response = await api.get(`/config/devices/${type}/${name}/status`); if (!this.deviceValues[type]) this.deviceValues[type] = {}; - this.deviceValues[type][name] = response.data.result; + this.deviceValues[type][name] = response.data; } catch (error) { console.error("Error fetching device values for", type, name, error); return null; diff --git a/assets/js/views/Log.vue b/assets/js/views/Log.vue index 9781087de..43de8d092 100644 --- a/assets/js/views/Log.vue +++ b/assets/js/views/Log.vue @@ -229,7 +229,7 @@ export default { count: showAll ? null : DEFAULT_COUNT, }, }); - this.lines = response.data?.result || []; + this.lines = response.data || []; this.$nextTick(() => { if (showAll) { this.scrollToTop(); @@ -258,7 +258,7 @@ export default { async updateAreas() { try { const response = await api.get("/system/log/areas"); - this.availableAreas = response.data?.result || []; + this.availableAreas = response.data || []; } catch (e) { console.error(e); } diff --git a/assets/js/views/Sessions.vue b/assets/js/views/Sessions.vue index 451ea9130..fe56fe9e2 100644 --- a/assets/js/views/Sessions.vue +++ b/assets/js/views/Sessions.vue @@ -673,7 +673,7 @@ export default { async loadSessions() { const response = await api.get("sessions"); // ensure sessions are sorted by created date - const sortedSessions = response.data?.result.sort((a, b) => { + const sortedSessions = response.data.sort((a, b) => { return new Date(a.created) - new Date(b.created); }); this.sessions = sortedSessions; diff --git a/server/mcp/openapi/openapi.go b/cmd/openapi/openapi.go similarity index 56% rename from server/mcp/openapi/openapi.go rename to cmd/openapi/openapi.go index 3e59f1fd8..366d62ff8 100644 --- a/server/mcp/openapi/openapi.go +++ b/cmd/openapi/openapi.go @@ -3,19 +3,13 @@ package main import ( "encoding/json" "log" - "net/url" "os" "github.com/getkin/kin-openapi/openapi3" ) func main() { - uri, err := url.Parse(os.Args[1]) - if err != nil { - log.Fatal(err) - } - - doc, err := openapi3.NewLoader().LoadFromURI(uri) + doc, err := openapi3.NewLoader().LoadFromFile(os.Args[1]) if err != nil { log.Fatal("failed to load OpenAPI spec:", err) } @@ -28,9 +22,7 @@ func main() { log.Fatal(err) } - if err := os.WriteFile("openapi.json", b, 0o644); err != nil { + if err := os.WriteFile(os.Args[2], b, 0o644); err != nil { log.Fatal(err) } - - log.Println("OpenAPI spec written to openapi.json") } diff --git a/go.mod b/go.mod index 1bbb1e388..0d63a218e 100644 --- a/go.mod +++ b/go.mod @@ -240,6 +240,7 @@ require ( tool ( github.com/dmarkham/enumer github.com/evcc-io/evcc/cmd/decorate + github.com/evcc-io/evcc/cmd/openapi github.com/gokrazy/tools/cmd/gok go.uber.org/mock/mockgen ) diff --git a/server/http_config_device_handler.go b/server/http_config_device_handler.go index c1692f26c..e6b55516a 100644 --- a/server/http_config_device_handler.go +++ b/server/http_config_device_handler.go @@ -73,7 +73,7 @@ func devicesConfigHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, res) + jsonWrite(w, res) } func deviceConfigMap[T any](class templates.Class, dev config.Device[T]) (map[string]any, error) { @@ -196,7 +196,7 @@ func deviceConfigHandler(w http.ResponseWriter, r *http.Request) { // TODO return application/yaml content type if type != template - jsonResult(w, res) + jsonWrite(w, res) } func deviceStatus[T any](name string, h config.Handler[T]) (T, error) { @@ -242,7 +242,7 @@ func deviceStatusHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, testInstance(instance)) + jsonWrite(w, testInstance(instance)) } func newDevice[T any](ctx context.Context, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T]) (*config.Config, error) { @@ -313,7 +313,7 @@ func newDeviceHandler(w http.ResponseWriter, r *http.Request) { Name: config.NameForID(conf.ID), } - jsonResult(w, res) + jsonWrite(w, res) } func updateDevice[T any](ctx context.Context, id int, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T]) error { @@ -387,7 +387,7 @@ func updateDeviceHandler(w http.ResponseWriter, r *http.Request) { ID: id, } - jsonResult(w, res) + jsonWrite(w, res) } func configurableDevice[T any](name string, h config.Handler[T]) (config.ConfigurableDevice[T], error) { @@ -529,7 +529,7 @@ func deleteDeviceHandler(site site.API) func(w http.ResponseWriter, r *http.Requ ID: id, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -595,5 +595,5 @@ func testConfigHandler(w http.ResponseWriter, r *http.Request) { // prevent context from being cancelled close(done) - jsonResult(w, testInstance(instance)) + jsonWrite(w, testInstance(instance)) } diff --git a/server/http_config_loadpoint_handler.go b/server/http_config_loadpoint_handler.go index baa45626b..b83c058e4 100644 --- a/server/http_config_loadpoint_handler.go +++ b/server/http_config_loadpoint_handler.go @@ -93,7 +93,7 @@ func loadpointsConfigHandler() http.HandlerFunc { return loadpointConfig(dev) }) - jsonResult(w, res) + jsonWrite(w, res) } } @@ -118,7 +118,7 @@ func loadpointConfigHandler() http.HandlerFunc { res := loadpointConfig(dev) - jsonResult(w, res) + jsonWrite(w, res) } } @@ -284,6 +284,6 @@ func deleteLoadpointHandler() http.HandlerFunc { ID: id, } - jsonResult(w, res) + jsonWrite(w, res) } } diff --git a/server/http_config_metadata_handler.go b/server/http_config_metadata_handler.go index fe3ce2684..2a373ad01 100644 --- a/server/http_config_metadata_handler.go +++ b/server/http_config_metadata_handler.go @@ -39,7 +39,7 @@ func templatesHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, res) + jsonWrite(w, res) return } @@ -56,7 +56,7 @@ func templatesHandler(w http.ResponseWriter, r *http.Request) { res = append(res, t) } - jsonResult(w, res) + jsonWrite(w, res) } // productsHandler returns the list of products by class @@ -101,5 +101,5 @@ func productsHandler(w http.ResponseWriter, r *http.Request) { return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name)) }) - jsonResult(w, res) + jsonWrite(w, res) } diff --git a/server/http_config_site_handler.go b/server/http_config_site_handler.go index 996900d24..f07279b9b 100644 --- a/server/http_config_site_handler.go +++ b/server/http_config_site_handler.go @@ -26,7 +26,7 @@ func siteHandler(site site.API) http.HandlerFunc { Ext: site.GetExtMeterRefs(), } - jsonResult(w, res) + jsonWrite(w, res) } } diff --git a/server/http_config_site_other_handler.go b/server/http_config_site_other_handler.go index cd8ab90e4..25c984ba8 100644 --- a/server/http_config_site_other_handler.go +++ b/server/http_config_site_other_handler.go @@ -30,11 +30,11 @@ func updateSponsortokenHandler(w http.ResponseWriter, r *http.Request) { settings.SetString(keys.SponsorToken, req.Token) setConfigDirty() - jsonResult(w, sponsor.Status()) + jsonWrite(w, sponsor.Status()) } func deleteSponsorTokenHandler(w http.ResponseWriter, r *http.Request) { settings.SetString(keys.SponsorToken, "") setConfigDirty() - jsonResult(w, true) + jsonWrite(w, true) } diff --git a/server/http_global_settings_handler.go b/server/http_global_settings_handler.go index 7a0227e32..e171ec521 100644 --- a/server/http_global_settings_handler.go +++ b/server/http_global_settings_handler.go @@ -17,14 +17,14 @@ import ( func settingsGetStringHandler(key string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { res, _ := settings.String(key) - jsonResult(w, res) + jsonWrite(w, res) } } func settingsDeleteHandler(key string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { settings.SetString(key, "") - jsonResult(w, true) + jsonWrite(w, true) } } @@ -41,7 +41,7 @@ func settingsSetDurationHandler(key string) http.HandlerFunc { settings.SetInt(key, int64(time.Second*time.Duration(val))) setConfigDirty() - jsonResult(w, val) + jsonWrite(w, val) } } @@ -67,7 +67,7 @@ func settingsSetYamlHandler(key string, other, struc any) http.HandlerFunc { settings.SetString(key, val) setConfigDirty() - jsonResult(w, val) + jsonWrite(w, val) } } @@ -94,7 +94,7 @@ func settingsSetJsonHandler(key string, valueChan chan<- util.Param, newStruc fu valueChan <- util.Param{Key: key, Val: struc} - jsonResult(w, true) + jsonWrite(w, true) } } @@ -105,6 +105,6 @@ func settingsDeleteJsonHandler(key string, valueChan chan<- util.Param, struc an valueChan <- util.Param{Key: key, Val: struc} - jsonResult(w, true) + jsonWrite(w, true) } } diff --git a/server/http_loadpoint_handler.go b/server/http_loadpoint_handler.go index a905670c3..e3f938fe8 100644 --- a/server/http_loadpoint_handler.go +++ b/server/http_loadpoint_handler.go @@ -37,7 +37,7 @@ func remoteDemandHandler(lp loadpoint.API) http.HandlerFunc { Demand: demand, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -69,7 +69,7 @@ func planHandler(lp loadpoint.API) http.HandlerFunc { Power: maxPower, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -131,7 +131,7 @@ func staticPlanPreviewHandler(lp loadpoint.API) http.HandlerFunc { Power: maxPower, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -189,7 +189,7 @@ func repeatingPlanPreviewHandler(lp loadpoint.API) http.HandlerFunc { Power: maxPower, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -234,7 +234,7 @@ func planEnergyHandler(lp loadpoint.API) http.HandlerFunc { Time: ts, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -247,7 +247,7 @@ func planRemoveHandler(lp loadpoint.API) http.HandlerFunc { } res := struct{}{} - jsonResult(w, res) + jsonWrite(w, res) } } @@ -271,7 +271,7 @@ func vehicleSelectHandler(site site.API, lp loadpoint.API) http.HandlerFunc { Vehicle: v.GetTitle(), } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -280,7 +280,7 @@ func vehicleRemoveHandler(lp loadpoint.API) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { lp.SetVehicle(nil) res := struct{}{} - jsonResult(w, res) + jsonWrite(w, res) } } @@ -289,6 +289,6 @@ func vehicleDetectHandler(lp loadpoint.API) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { lp.StartVehicleDetection() res := struct{}{} - jsonResult(w, res) + jsonWrite(w, res) } } diff --git a/server/http_session_handler.go b/server/http_session_handler.go index 6102a56c8..3fded984a 100644 --- a/server/http_session_handler.go +++ b/server/http_session_handler.go @@ -87,7 +87,7 @@ func sessionHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, res) + jsonWrite(w, res) } // deleteSessionHandler removes session in sessions table with given id @@ -107,7 +107,7 @@ func deleteSessionHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, res) + jsonWrite(w, res) } // updateSessionHandler updates the data of an existing session diff --git a/server/http_site_handler.go b/server/http_site_handler.go index ff8fb98e3..aa2eb8a9c 100644 --- a/server/http_site_handler.go +++ b/server/http_site_handler.go @@ -81,16 +81,12 @@ func jsonHandler(h http.Handler) http.Handler { }) } -func jsonWrite(w http.ResponseWriter, content interface{}) { - if err := json.NewEncoder(w).Encode(content); err != nil { +func jsonWrite(w http.ResponseWriter, data interface{}) { + if err := json.NewEncoder(w).Encode(data); err != nil { log.ERROR.Printf("httpd: failed to encode JSON: %v", err) } } -func jsonResult(w http.ResponseWriter, res interface{}) { - jsonWrite(w, map[string]interface{}{"result": res}) -} - func jsonError(w http.ResponseWriter, status int, err error) { w.WriteHeader(status) @@ -129,7 +125,7 @@ func handler[T any](conv func(string) (T, error), set func(T) error, get func() return } - jsonResult(w, get()) + jsonWrite(w, get()) } } @@ -175,7 +171,7 @@ func durationHandler(set func(time.Duration) error, get func() time.Duration) ht // getHandler returns api results func getHandler[T any](get func() T) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - jsonResult(w, get()) + jsonWrite(w, get()) } } @@ -199,7 +195,7 @@ func updateSmartCostLimit(site site.API, setLimit func(loadpoint.API, *float64)) setLimit(lp, val) } - jsonResult(w, val) + jsonWrite(w, val) } } @@ -221,7 +217,7 @@ func updateBatteryMode(site site.API) http.HandlerFunc { site.SetBatteryModeExternal(val) - jsonResult(w, site.GetBatteryModeExternal()) + jsonWrite(w, site.GetBatteryModeExternal()) } } @@ -258,7 +254,7 @@ func stateHandler(cache *util.ParamCache) http.HandlerFunc { return } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -306,7 +302,7 @@ func tariffHandler(site site.API) http.HandlerFunc { Rates: rates, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -318,12 +314,12 @@ func socketHandler(hub *SocketHub) http.HandlerFunc { } func logAreasHandler(w http.ResponseWriter, r *http.Request) { - jsonResult(w, logstash.Areas()) + jsonWrite(w, logstash.Areas()) } func clearCacheHandler(w http.ResponseWriter, r *http.Request) { util.ResetCached() - jsonResult(w, "OK") + jsonWrite(w, "OK") } func logHandler(w http.ResponseWriter, r *http.Request) { @@ -351,7 +347,7 @@ func logHandler(w http.ResponseWriter, r *http.Request) { return } - jsonResult(w, log) + jsonWrite(w, log) } // adminPasswordValid validates the admin password and returns true if valid diff --git a/server/http_vehicle_handler.go b/server/http_vehicle_handler.go index 907381c28..76f77b9ac 100644 --- a/server/http_vehicle_handler.go +++ b/server/http_vehicle_handler.go @@ -36,7 +36,7 @@ func minSocHandler(site site.API) http.HandlerFunc { Soc: v.GetMinSoc(), } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -65,7 +65,7 @@ func limitSocHandler(site site.API) http.HandlerFunc { Soc: v.GetLimitSoc(), } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -116,7 +116,7 @@ func planSocHandler(site site.API) http.HandlerFunc { Time: ts, } - jsonResult(w, res) + jsonWrite(w, res) } } @@ -146,7 +146,7 @@ func addRepeatingPlansHandler(site site.API) http.HandlerFunc { return } - jsonResult(w, plansWrapper) + jsonWrite(w, plansWrapper) } } @@ -167,6 +167,6 @@ func planSocRemoveHandler(site site.API) http.HandlerFunc { } res := struct{}{} - jsonResult(w, res) + jsonWrite(w, res) } } diff --git a/server/mcp/openapi.json b/server/mcp/openapi.json index b38128dc5..27c4f090c 100644 --- a/server/mcp/openapi.json +++ b/server/mcp/openapi.json @@ -20,7 +20,7 @@ } }, "current": { - "description": "Electric current in amps", + "description": "Electric current in A", "in": "path", "name": "current", "required": true, @@ -29,7 +29,7 @@ } }, "delay": { - "description": "Time in seconds. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#delay)\n", + "description": "Duration in seconds.", "in": "path", "name": "delay", "required": true, @@ -38,7 +38,7 @@ } }, "enable": { - "description": "Charging mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#mode)\n", + "description": "Charging mode.", "in": "path", "name": "enable", "required": true, @@ -71,7 +71,7 @@ } }, "id": { - "description": "The index. Starts with 1.", + "description": "Loadpoint index starting at 1", "in": "path", "name": "id", "required": true, @@ -80,7 +80,7 @@ } }, "logAreas": { - "description": "Timezone in IANA format - [See Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List)", + "description": "Comma-separated list of log areas", "explode": true, "in": "query", "name": "areas", @@ -89,7 +89,7 @@ } }, "logLevel": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/log#log)", + "description": "Log level", "in": "query", "name": "level", "required": true, @@ -106,7 +106,7 @@ } }, "phases": { - "description": "Number of phases. (0: auto, 1: 1-phase, 3: 3-phase) [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#phases)\n", + "description": "Number of phases. (0: auto, 1: 1-phase, 3: 3-phase)", "in": "path", "name": "phases", "required": true, @@ -159,7 +159,7 @@ } }, "vehicleName": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/vehicles#name)", + "description": "Vehicle name", "in": "path", "name": "name", "required": true, @@ -168,7 +168,7 @@ } }, "weekdays": { - "description": "The Weekdays - [See documentation](https://docs.evcc.io/en/docs/features/plans#repeating-plans)", + "description": "The Weekdays", "in": "path", "name": "weekdays", "required": true, @@ -184,7 +184,7 @@ "schema": { "properties": { "result": { - "description": "Battery mode. 0: unknown, 1: normal, 2: hold, 3: charge\n", + "description": "Battery mode. 0: unknown, 1: normal, 2: hold, 3: charge", "maximum": 3, "minimum": 0, "type": "integer" @@ -194,7 +194,7 @@ } } }, - "description": "Battery mode." + "description": "Battery mode" }, "BlankResponse": { "description": "Success - Blank response" @@ -337,7 +337,7 @@ }, "schemas": { "BatteryMode": { - "description": "TODO", + "description": "Battery mode", "enum": [ "unknown", "normal", @@ -422,13 +422,13 @@ "type": "array" }, "Current": { - "description": "Electric current in amps", + "description": "Electric current in A", "example": 16, "minimum": 0, "type": "number" }, "Delay": { - "description": "Time in seconds. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#delay)\n", + "description": "Duration in seconds.", "example": 60, "type": "integer" }, @@ -439,46 +439,54 @@ "type": "number" }, "HourMinuteTime": { - "description": "Time in `HOURS:MINUTES` format", + "description": "Time in `HH:MM` format", "example": "12:30", "format": "HH:MM", "pattern": "[0-1][0-9]:[0-5][0-9]", "type": "string" }, "IANATimeZone": { - "description": "Timezone in IANA format - [See Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List)", + "description": "Timezone in IANA format", "example": "Europe/Berlin", + "externalDocs": { + "url": "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List" + }, "type": "string" }, "Id": { - "description": "The index. Starts with 1.", + "description": "Loadpoint index starting at 1.", "example": 1, "minimum": 1, "type": "integer" }, "LoadpointName": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#title)", "example": "Garage", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#title" + }, "type": "string" }, "LogArea": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/log#levels)", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/log#levels" + }, "type": "string" }, "LogAreas": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/log#levels)", "example": [ "lp-1", "site", "db" ], + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/log#levels" + }, "items": { "$ref": "#/components/schemas/LogArea" }, "type": "array" }, "LogLevel": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/log#log)", "enum": [ "FATAL", "ERROR", @@ -488,10 +496,13 @@ "TRACE" ], "example": "DEBUG", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/log#log" + }, "type": "string" }, "Mode": { - "description": "Charging mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#mode)\n", + "description": "Charging mode.", "enum": [ "off", "now", @@ -502,23 +513,22 @@ }, "Password": { "description": "Admin password", - "example": "passWord1234!", "type": "string" }, "Phases": { - "description": "Number of phases. (0: auto, 1: 1-phase, 3: 3-phase) [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#phases)\n", + "description": "Number of phases. (0: auto, 1: 1-phase, 3: 3-phase)", "enum": [ - 0, - 1, - 3 + "0", + "1", + "3" ], - "example": 3, - "type": "integer" + "example": "3", + "type": "string" }, "PlanRates": { "properties": { "duration": { - "description": "Charging length", + "description": "Duration in s", "minimum": 0, "type": "integer" }, @@ -541,7 +551,7 @@ "type": "number" }, "Precondition": { - "description": "Late charging duration in seconds. [Read more.](https://docs.evcc.io/en/docs/features/plans#late-charging)", + "description": "Late charging duration in seconds.", "example": 3600, "minimum": 0, "type": "integer" @@ -556,7 +566,7 @@ "$ref": "#/components/schemas/Timestamp" }, "value": { - "description": "Cost of charging interval", + "description": "Cost", "minimum": 0, "type": "number" } @@ -570,10 +580,12 @@ "type": "array" }, "RepeatingPlan": { - "description": "[See documentation](https://docs.evcc.io/en/docs/features/plans#repeating-plans)", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans#repeating-plans" + }, "properties": { "active": { - "description": "Whether evcc should take the plan into account. `false` means that evcc ignores the plan.", + "description": "Set plan active.", "type": "boolean" }, "precondition": { @@ -613,11 +625,13 @@ "type": "number" }, "State": { - "description": "The actual state structure is not documented yet. Most values should be self-explanatory. Note: While the overall structure is quite stable, details may change between releases.\n", + "description": "The actual state structure is not documented yet. Most values should be self-explanatory. Note: While the overall structure is quite stable, details may change between releases.", "type": "object" }, "StaticEnergyPlan": { - "description": "[See documentation](https://docs.evcc.io/en/docs/features/plans#energy-amount-plan)", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans#energy-amount-plan" + }, "properties": { "energy": { "$ref": "#/components/schemas/Energy" @@ -632,7 +646,9 @@ "type": "object" }, "StaticSocPlan": { - "description": "[See documentation](https://docs.evcc.io/en/docs/features/plans#create-charging-plan)", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans#create-charging-plan" + }, "properties": { "precondition": { "$ref": "#/components/schemas/Precondition" @@ -648,31 +664,35 @@ }, "Timestamp": { "description": "Timestamp in RFC3339 format", - "example": "2025-07-19T12:30:00.000Z", + "example": "2025-07-19T12:30:00Z", "format": "date-time", "type": "string" }, "VehicleName": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/vehicles#name)", "example": "vehicle_1", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/vehicles#name" + }, "minLength": 1, "pattern": "[a-zA-Z0-9_.:-]+", "type": "string" }, "VehicleTitle": { - "description": "[See documentation](https://docs.evcc.io/en/docs/reference/configuration/vehicles#title)", "example": "blauer e-Golf", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/vehicles#title" + }, "type": "string" }, "Weekdays": { - "description": "The Weekdays - [See documentation](https://docs.evcc.io/en/docs/features/plans#repeating-plans)", + "description": "The Weekdays", "example": [ 1, 3, 4 ], "items": { - "description": "0: Sunday\n1: Monday\n2: Tuesday\n3: Wednesday\n4: Thursday\n5: Friday\n6: Saturday\n", + "description": "0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday", "maximum": 6, "minimum": 0, "type": "integer" @@ -690,14 +710,19 @@ } }, "info": { - "title": "evcc REST-API", - "version": "latest" + "contact": { + "url": "https://github.com/evcc-io/evcc" + }, + "description": "Solar charging. Super simple.", + "title": "evcc", + "version": "0.2.0" }, "openapi": "3.0.3", "paths": { "/auth/login": { "post": { - "description": "Login returns an auth cookie required for all protected endpoints.\n", + "description": "Administrator login. Returns authorization cookie required for all protected endpoints.", + "operationId": "login", "requestBody": { "content": { "application/json": { @@ -732,13 +757,14 @@ }, "summary": "Login", "tags": [ - "Auth" + "auth" ] } }, "/auth/logout": { "post": { - "description": "Deletes the authorization cookie", + "description": "Logout and delete authorization cookie", + "operationId": "logout", "responses": { "200": { "description": "Success", @@ -757,13 +783,13 @@ }, "summary": "Logout", "tags": [ - "Auth" + "auth" ] } }, "/auth/password": { "put": { - "description": "Changes the admin password.\n", + "description": "Changes the admin password.", "requestBody": { "content": { "application/json": { @@ -784,7 +810,7 @@ }, "summary": "Change admin password", "tags": [ - "Auth" + "auth" ] } }, @@ -809,13 +835,16 @@ }, "summary": "Authentication status", "tags": [ - "Auth" + "auth" ] } }, "/batterydischargecontrol/{enable}": { "post": { - "description": "Prevent home battery discharge during vehicle fast charging. [Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Prevent home battery discharge during vehicle fast charging.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "parameters": [ { "$ref": "#/components/parameters/enable" @@ -828,13 +857,16 @@ }, "summary": "Control battery-discharge", "tags": [ - "Home Battery" + "battery" ] } }, "/batterygridchargelimit": { "delete": { - "description": "Remove battery grid charge limit. [Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Remove battery grid charge limit.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "responses": { "200": { "$ref": "#/components/responses/NullResult" @@ -842,13 +874,16 @@ }, "summary": "Remove battery grid charge limit", "tags": [ - "Home Battery" + "battery" ] } }, "/batterygridchargelimit/{cost}": { "post": { - "description": "Charge home battery from grid when price or emissions are below the threshold.\nUses price if a dynamic tariff exists. Uses emissions if a CO₂-tariff is configured. Ignored otherwise.\n[Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Charge home battery from grid when price or emissions are below the threshold. Uses price if a dynamic tariff exists. Uses emissions if a CO₂-tariff is configured. Ignored otherwise.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "parameters": [ { "$ref": "#/components/parameters/costLimit" @@ -861,7 +896,7 @@ }, "summary": "Set battery grid charge limit", "tags": [ - "Home Battery" + "battery" ] } }, @@ -875,13 +910,13 @@ }, "summary": "Disable external battery control", "tags": [ - "Home Battery" + "battery" ] } }, "/batterymode/{batteryMode}": { "post": { - "description": "Directly controls the mode of all controllable batteries. evcc behavior like \"price limit\" or \"prevent discharge while fast charging\" is overruled. External mode resets after 60s. The external system has to call this endpoint regularly.", + "description": "Directly controls the mode of all controllable batteries. evcc behavior like 'price limit' or 'prevent discharge while fast charging' is overruled. External mode resets after 60s. The external system has to call this endpoint regularly.", "parameters": [ { "$ref": "#/components/parameters/batteryMode" @@ -894,13 +929,16 @@ }, "summary": "Set external battery mode", "tags": [ - "Home Battery" + "battery" ] } }, "/buffersoc/{soc}": { "post": { - "description": "Set battery buffer SoC. [Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Set battery buffer SoC.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "parameters": [ { "$ref": "#/components/parameters/soc" @@ -913,13 +951,16 @@ }, "summary": "Set battery buffer SoC", "tags": [ - "Home Battery" + "battery" ] } }, "/bufferstartsoc/{soc}": { "post": { - "description": "Set battery buffer start SoC. [Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Set battery buffer start SoC.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "parameters": [ { "$ref": "#/components/parameters/soc" @@ -932,13 +973,14 @@ }, "summary": "Set battery buffer start SoC", "tags": [ - "Home Battery" + "battery" ] } }, "/health": { "get": { "description": "Returns 200 if the evcc loop runs as expected.", + "operationId": "healthCheck", "responses": { "200": { "content": { @@ -954,13 +996,16 @@ }, "summary": "Health check", "tags": [ - "General" + "general" ] } }, "/loadpoints/{id}/batteryboost/{enable}": { "post": { - "description": "Enables or disables battery boost. [Read more.](https://docs.evcc.io/en/docs/features/battery#battery-boost)\n", + "description": "Enable or disable battery boost.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery#battery-boost" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -976,13 +1021,16 @@ }, "summary": "Set battery boost", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/disable/delay/{delay}": { "post": { - "description": "Specifies the delay before charging stops in solar mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints)\n", + "description": "Delay before charging stops in solar mode.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -998,13 +1046,16 @@ }, "summary": "Disable threshold-delay", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/disable/threshold/{threshold}": { "post": { - "description": "Specifies the grid draw power to stop charging in solar mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#threshold-1)\n", + "description": "Specifies the grid draw power to stop charging in solar mode.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#threshold-1" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1020,13 +1071,16 @@ }, "summary": "Disable threshold", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/enable/delay/{delay}": { "post": { - "description": "Specifies the delay before charging starts in solar mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#delay)\n", + "description": "Delay before charging starts in solar mode.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#delay" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1042,13 +1096,16 @@ }, "summary": "Enable threshold-delay", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/enable/threshold/{threshold}": { "post": { - "description": "Specifies the available surplus power to start charging in solar mode. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#threshold)\n", + "description": "Specifies the available surplus power to start charging in solar mode.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#threshold" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1064,13 +1121,16 @@ }, "summary": "Enable threshold", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/limitenergy/{energy}": { "post": { - "description": "Updates the energy limit of the loadpoint. Only available for guest vehicles and vehicles with unknown SoC. Limit is removed on vehicle disconnect. [Read more.](https://docs.evcc.io/en/docs/features/limit)\n", + "description": "Updates the energy limit of the loadpoint. Only available for guest vehicles and vehicles with unknown SoC. Limit is removed on vehicle disconnect.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/limit" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1086,13 +1146,16 @@ }, "summary": "Update energy limit", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/limitsoc/{soc}": { "post": { - "description": "Updates the SoC limit of the loadpoint. Requires a connected vehicle with known SoC. Limit is maintained across charging sessions. [Read more.](https://docs.evcc.io/en/docs/features/limit)\n", + "description": "Updates the SoC limit of the loadpoint. Requires a connected vehicle with known SoC. Limit is maintained across charging sessions.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/limit" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1108,13 +1171,13 @@ }, "summary": "Update limit SoC", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/maxcurrent/{current}": { "post": { - "description": "Updates the maximum current of the loadpoint.\n", + "description": "Updates the maximum current of the loadpoint.", "parameters": [ { "$ref": "#/components/parameters/id" @@ -1130,13 +1193,13 @@ }, "summary": "Update maximum current", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/mincurrent/{current}": { "post": { - "description": "Updates the minimum current of the loadpoint.\n", + "description": "Updates the minimum current of the loadpoint.", "parameters": [ { "$ref": "#/components/parameters/id" @@ -1152,13 +1215,16 @@ }, "summary": "Update minimum current", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/mode/{mode}": { "post": { - "description": "Changes the charging behavior of the loadpoint. [Read more.](https://docs.evcc.io/en/docs/features/solar-charging)\n", + "description": "Changes the charging behavior of the loadpoint.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/solar-charging" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1186,13 +1252,16 @@ }, "summary": "Update charge mode", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/phases/{phases}": { "post": { - "description": "Updates the allowed phases of the loadpoint. Selects the desired phase mode for chargers with automatic phase switching. For manual phase switching chargers (via cable or Lasttrennschalter) this value tells evcc the actual phases. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#phases)\n", + "description": "Updates the allowed phases of the loadpoint. Selects the desired phase mode for chargers with automatic phase switching. For manual phase switching chargers (via cable or Lasttrennschalter) this value tells evcc the actual phases.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#phases" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1206,18 +1275,21 @@ "$ref": "#/components/responses/NumberResult" }, "400": { - "description": "Invalid phases-value. You have most likely entered the value 0 for a wallbox that cannot switch phases automatically. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#phases)" + "description": "Invalid phases-value. You have most likely entered the value 0 for a wallbox that cannot switch phases automatically." } }, "summary": "Update allowed phases", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/plan": { "get": { - "description": "Returns the current charging plan for this loadpoint. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Returns the current charging plan for this loadpoint.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1257,13 +1329,16 @@ }, "summary": "Plan rates", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/plan/energy": { "delete": { - "description": "Deletes the charging plan. Only available when a vehicle with unknown SoC is connected. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Delete charging plan. Only available when a vehicle without SoC is connected.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1274,15 +1349,18 @@ "$ref": "#/components/responses/EmptyResult" } }, - "summary": "Deletes the energy-based charging plan", + "summary": "Delete energy-based charging plan", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/plan/energy/{energy}/{timestamp}": { "post": { - "description": "Creates a charging plan with fixed time and energy target. Only available when a vehicle with unknown SoC is connected. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Create charging plan with fixed time and energy target. Only available when a vehicle without SoC is connected.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1311,15 +1389,18 @@ "description": "Success" } }, - "summary": "Sets an energy-based charging plan", + "summary": "Set energy-based charging plan", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/plan/repeating/preview/{soc}/{weekdays}/{hourMinuteTime}/{timezone}": { "get": { - "description": "Simulates a repeating charging plan and returns the result. Does not alter the actual charging plan. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Simulate repeating charging plan and return the result. Does not alter the actual charging plan.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1344,54 +1425,22 @@ }, "summary": "Repeating plan preview", "tags": [ - "Loadpoints" + "loadpoints" ] } }, - "/loadpoints/{id}/plan/static/preview/{type}/{goal}/{timestamp}": { + "/loadpoints/{id}/plan/static/preview/energy/{energy}/{timestamp}": { "get": { - "description": "Simulates a charging plan and returns the result. Does not alter the actual charging plan. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Simulate charging plan based on energy goal. Does not alter the actual charging plan.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/id" }, { - "description": "Energy or SoC to reach.", - "examples": { - "socAvailable": { - "summary": "If SoC is available =\u003e specify SoC in %", - "value": 80 - }, - "socNotAvailable": { - "summary": "If SoC is not available =\u003e specify energy in kWh", - "value": 25.5 - } - }, - "in": "path", - "name": "goal", - "required": true, - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/Soc" - }, - { - "$ref": "#/components/schemas/Energy" - } - ] - } - }, - { - "in": "path", - "name": "type", - "required": true, - "schema": { - "enum": [ - "soc", - "energy" - ], - "type": "string" - } + "$ref": "#/components/parameters/energy" }, { "$ref": "#/components/parameters/timestamp" @@ -1402,15 +1451,46 @@ "$ref": "#/components/responses/PlanRatesResult" } }, - "summary": "Preview of a charging plan", + "summary": "Simulate energy-based charging plan", "tags": [ - "Loadpoints" + "loadpoints" + ] + } + }, + "/loadpoints/{id}/plan/static/preview/soc/{soc}/{timestamp}": { + "get": { + "description": "Simulate charging plan based on SoC goal. Does not alter the actual charging plan.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, + "parameters": [ + { + "$ref": "#/components/parameters/id" + }, + { + "$ref": "#/components/parameters/soc" + }, + { + "$ref": "#/components/parameters/timestamp" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/PlanRatesResult" + } + }, + "summary": "Simulate soc-based charging plan", + "tags": [ + "loadpoints" ] } }, "/loadpoints/{id}/priority/{priority}": { "post": { - "description": "Sets the priority of the loadpoint. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/loadpoints#priority)\n", + "description": "Set loadpoint priority.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/loadpoints#priority" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1434,13 +1514,16 @@ }, "summary": "Set priority", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/smartcostlimit": { "delete": { - "description": "Removes the price or emission limit for fast-charging with grid energy. [Read more.](https://docs.evcc.io/en/docs/features/dynamic-prices)\n", + "description": "Delete cost or emission limit for fast-charging with grid energy.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/dynamic-prices" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1451,15 +1534,18 @@ "$ref": "#/components/responses/NullResult" } }, - "summary": "Remove smart charging cost limit", + "summary": "Delete smart charging cost limit", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/smartcostlimit/{cost}": { "post": { - "description": "Sets the price or emission limit for fast-charging with grid energy. [Read more.](https://docs.evcc.io/en/docs/features/dynamic-prices)\n", + "description": "Set cost or emission limit for fast-charging with grid energy.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/dynamic-prices" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1475,13 +1561,16 @@ }, "summary": "Set smart charging cost limit", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/vehicle": { "delete": { - "description": "Removes the association of a vehicle to the loadpoint. Connected vehicle is treated as guest vehicle. [Read more.](https://docs.evcc.io/en/docs/features/vehicle)\n", + "description": "Remove vehicle from loadpoint. Connected vehicle is treated as guest vehicle.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/vehicle" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1492,13 +1581,16 @@ "$ref": "#/components/responses/EmptyResult" } }, - "summary": "Delete vehicle", + "summary": "Remove vehicle", "tags": [ - "Loadpoints" + "loadpoints" ] }, "patch": { - "description": "Starts the automaticvehicle detection process. [Read more.](https://docs.evcc.io/en/docs/features/vehicle)\n", + "description": "Starts the automatic vehicle detection process.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/vehicle" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1511,13 +1603,16 @@ }, "summary": "Start vehicle detection", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/loadpoints/{id}/vehicle/{name}": { "post": { - "description": "Changes the association of a vehicle to the loadpoint. [Read more.](https://docs.evcc.io/en/docs/features/vehicle)\n", + "description": "Assigns vehicle to loadpoint.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/vehicle" + }, "parameters": [ { "$ref": "#/components/parameters/id" @@ -1550,13 +1645,16 @@ }, "summary": "Assign vehicle", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/prioritysoc/{soc}": { "post": { - "description": "Set battery priority SoC. [Read more.](https://docs.evcc.io/en/docs/features/battery)\n", + "description": "Set battery priority SoC.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/battery" + }, "parameters": [ { "$ref": "#/components/parameters/soc" @@ -1569,13 +1667,16 @@ }, "summary": "Set battery priority SoC", "tags": [ - "Home Battery" + "battery" ] } }, "/residualpower/{power}": { "post": { - "description": "Sets target operating point of the control loop. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/site#residualpower)\n", + "description": "Set grid connection operating point.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/site#residualpower" + }, "parameters": [ { "$ref": "#/components/parameters/power" @@ -1588,13 +1689,16 @@ }, "summary": "Set grid residual power", "tags": [ - "Home Battery" + "battery" ] } }, "/session/{id}": { "delete": { - "description": "Delete charging session. [Read more.](https://docs.evcc.io/en/docs/features/sessions)\n", + "description": "Delete charging session.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/sessions" + }, "responses": { "200": { "$ref": "#/components/responses/NullResult" @@ -1602,7 +1706,7 @@ }, "summary": "Delete charging session", "tags": [ - "Sessions" + "sessions" ] }, "parameters": [ @@ -1611,7 +1715,10 @@ } ], "put": { - "description": "Update vehicle of charging session. [Read more.](https://docs.evcc.io/en/docs/features/sessions)\n", + "description": "Update vehicle of charging session.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/sessions" + }, "requestBody": { "content": { "application/json": { @@ -1637,13 +1744,16 @@ }, "summary": "Update vehicle of charging session", "tags": [ - "Sessions" + "sessions" ] } }, "/sessions": { "get": { - "description": "Returns a list of charging sessions. [Read more.](https://docs.evcc.io/en/docs/features/sessions)\n", + "description": "Returns a list of charging sessions.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/sessions" + }, "parameters": [ { "description": "Response format (default json)", @@ -1712,13 +1822,16 @@ }, "summary": "Charging sessions", "tags": [ - "Sessions" + "sessions" ] } }, "/settings/telemetry": { "get": { - "description": "Returns the current telemetry status. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/telemetry)\n", + "description": "Returns the current telemetry status.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/telemetry" + }, "responses": { "200": { "$ref": "#/components/responses/BooleanResult" @@ -1726,13 +1839,16 @@ }, "summary": "Telemetry status", "tags": [ - "System" + "system" ] } }, "/settings/telemetry/{enable}": { "post": { - "description": "Enable or disable telemetry. Note: Telemetry requires [sponsorship](https://docs.evcc.io/en/docs/sponsorship). [Read more.](https://docs.evcc.io/en/docs/reference/configuration/telemetry)\n", + "description": "Enable or disable telemetry. Note: Telemetry requires sponsorship.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/telemetry" + }, "parameters": [ { "$ref": "#/components/parameters/enable" @@ -1748,13 +1864,13 @@ }, "summary": "Enable/disable telemetry", "tags": [ - "System" + "system" ] } }, "/smartcostlimit": { "delete": { - "description": "Conveniance method to remove limit for all loadpoints at once. Value is applied to each individual loadpoint.\n", + "description": "Convenience method to remove limit for all loadpoints at once. Value is applied to each individual loadpoint.", "responses": { "200": { "$ref": "#/components/responses/NullResult" @@ -1762,13 +1878,13 @@ }, "summary": "Remove smart charging cost limit for all loadpoints.", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/smartcostlimit/{cost}": { "post": { - "description": "Conveniance method to set smart charging cost limit for all loadpoints at once. Value is applied to each individual loadpoint.\n", + "description": "Conveniance method to set smart charging cost limit for all loadpoints at once. Value is applied to each individual loadpoint.", "parameters": [ { "$ref": "#/components/parameters/costLimit" @@ -1781,13 +1897,17 @@ }, "summary": "Set smart charging cost limit for all loadpoints", "tags": [ - "Loadpoints" + "loadpoints" ] } }, "/state": { "get": { - "description": "Returns the complete state of the system. This structure is used by the UI. It can be filtered by [JQ](https://jqlang.github.io/jq/) to only return a subset of the data. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/state)\n", + "description": "Returns the complete state of the system. This structure is used by the UI. It can be filtered by JQ to only return a subset of the data.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/state" + }, + "operationId": "getState", "parameters": [ { "description": "Filter the state with JQ", @@ -1827,13 +1947,16 @@ }, "summary": "System state", "tags": [ - "General" + "general" ] } }, "/system/log": { "get": { - "description": "Returns the latest log lines. [Read more.](https://docs.evcc.io/en/docs/reference/configuration/log)\n", + "description": "Returns the latest log lines.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/reference/configuration/log" + }, "parameters": [ { "$ref": "#/components/parameters/logAreas" @@ -1899,13 +2022,13 @@ ], "summary": "Logs", "tags": [ - "System" + "system" ] } }, "/system/log/areas": { "get": { - "description": "Returns a list of all log areas (e.g. `lp-1`, `site`, `db`).\n", + "description": "Returns a list of all log areas (e.g. `lp-1`, `site`, `db`).", "responses": { "200": { "content": { @@ -1933,13 +2056,13 @@ ], "summary": "List of all log areas", "tags": [ - "System" + "system" ] } }, "/system/shutdown": { "post": { - "description": "Shuts down the evcc instance. There is no reboot command. We expect the underlying system (docker, systemd, etc.) to restart the evcc instance once it's terminated.\n", + "description": "Shut down instance. There is no reboot command. We expect the underlying system (docker, systemd, etc.) to restart the evcc instance once it's terminated.", "responses": { "204": { "$ref": "#/components/responses/BlankResponse" @@ -1955,13 +2078,16 @@ ], "summary": "Shutdown evcc", "tags": [ - "System" + "system" ] } }, "/tariff/{type}": { "get": { - "description": "Returns the prices or emission values for the upcoming hours [Read more.](https://docs.evcc.io/en/docs/devices/tariffs)\n", + "description": "Returns the prices or emission values for the upcoming hours", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/devices/tariffs" + }, "parameters": [ { "description": "Tariff type", @@ -2007,13 +2133,16 @@ }, "summary": "Tariff information", "tags": [ - "Tariffs" + "tariffs" ] } }, "/vehicles/{name}/limitsoc/{soc}": { "post": { - "description": "Charging will stop when this SoC is reached. [Read more.](https://docs.evcc.io/en/docs/features/limits)\n", + "description": "Charging will stop when this SoC is reached.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/limits" + }, "parameters": [ { "$ref": "#/components/parameters/vehicleName" @@ -2029,13 +2158,16 @@ }, "summary": "Set SoC limit", "tags": [ - "Vehicles" + "vehicles" ] } }, "/vehicles/{name}/minsoc/{soc}": { "post": { - "description": "Vehicle will be fast-charged until this SoC is reached. [Read more.](https://docs.evcc.io/en/docs/features/limits)\n", + "description": "Vehicle will be fast-charged until this SoC is reached.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/limits" + }, "parameters": [ { "$ref": "#/components/parameters/vehicleName" @@ -2051,13 +2183,16 @@ }, "summary": "Set minimum SoC", "tags": [ - "Vehicles" + "vehicles" ] } }, "/vehicles/{name}/plan/repeating": { "post": { - "description": "Updates the repeating charging plan. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Updates the repeating charging plan.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/vehicleName" @@ -2092,13 +2227,16 @@ }, "summary": "Update repeating plans", "tags": [ - "Vehicles" + "vehicles" ] } }, "/vehicles/{name}/plan/soc": { "delete": { - "description": "Deletes the charging plan [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Delete the charging plan", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/vehicleName" @@ -2111,13 +2249,16 @@ }, "summary": "Delete a SoC-based charging plan", "tags": [ - "Vehicles" + "vehicles" ] } }, "/vehicles/{name}/plan/soc/{soc}/{timestamp}": { "post": { - "description": "Creates a charging plan with fixed time and SoC target. [Read more.](https://docs.evcc.io/en/docs/features/plans)\n", + "description": "Create charging plan with fixed time and SoC target.", + "externalDocs": { + "url": "https://docs.evcc.io/en/docs/features/plans" + }, "parameters": [ { "$ref": "#/components/parameters/vehicleName" @@ -2155,35 +2296,35 @@ }, "summary": "Set a SoC-based charging plan", "tags": [ - "Vehicles" + "vehicles" ] } } }, "tags": [ { - "name": "General" + "name": "auth" }, { - "name": "Loadpoints" + "name": "battery" }, { - "name": "Vehicles" + "name": "general" }, { - "name": "Home Battery" + "name": "loadpoints" }, { - "name": "Tariffs" + "name": "sessions" }, { - "name": "Sessions" + "name": "system" }, { - "name": "Auth" + "name": "tariffs" }, { - "name": "System" + "name": "vehicles" } ] } \ No newline at end of file diff --git a/server/openapi.go b/server/openapi.go new file mode 100644 index 000000000..339045e90 --- /dev/null +++ b/server/openapi.go @@ -0,0 +1,3 @@ +package server + +//go:generate go tool openapi openapi.yaml mcp/openapi.json diff --git a/server/openapi.yaml b/server/openapi.yaml index 6b5b7ca6b..f0c1d4962 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: evcc description: Solar charging. Super simple. - version: latest + version: "0.2.0" contact: url: https://github.com/evcc-io/evcc servers: