diff --git a/api/plans.go b/api/plans.go index 2bbe2de76..65eb9e40e 100644 --- a/api/plans.go +++ b/api/plans.go @@ -1,6 +1,6 @@ package api -type RepeatingPlanStruct struct { +type RepeatingPlan struct { Weekdays []int `json:"weekdays"` // 0-6 (Sunday-Saturday) Time string `json:"time"` // HH:MM Tz string `json:"tz"` // timezone in IANA format diff --git a/assets/js/components/ChargingPlans/ChargingPlan.vue b/assets/js/components/ChargingPlans/ChargingPlan.vue index 433e4aff9..d043c4a28 100644 --- a/assets/js/components/ChargingPlans/ChargingPlan.vue +++ b/assets/js/components/ChargingPlans/ChargingPlan.vue @@ -181,7 +181,11 @@ export default defineComponent({ return null; }, repeatingPlans(): RepeatingPlan[] { - if (this.vehicle && this.vehicle.repeatingPlans.length > 0) { + if ( + this.vehicle && + this.vehicle.repeatingPlans && + this.vehicle.repeatingPlans.length > 0 + ) { return [...this.vehicle.repeatingPlans]; } return []; @@ -301,7 +305,7 @@ export default defineComponent({ } }, updateRepeatingPlans(plans: RepeatingPlan[]): void { - api.post(`${this.apiVehicle}plan/repeating`, { plans }); + api.post(`${this.apiVehicle}plan/repeating`, plans); }, setMinSoc(soc: number): void { api.post(`${this.apiVehicle}minsoc/${soc}`); diff --git a/assets/js/components/ChargingPlans/types.d.ts b/assets/js/components/ChargingPlans/types.d.ts index c93f60623..2a667897f 100644 --- a/assets/js/components/ChargingPlans/types.d.ts +++ b/assets/js/components/ChargingPlans/types.d.ts @@ -13,7 +13,7 @@ export interface PlanWrapper { planId: number; planTime: Date; duration: number; - plan: Rate[]; + plan: Rate[] | null; power: number; } diff --git a/assets/js/types/evcc.ts b/assets/js/types/evcc.ts index 4e48297c7..7745aa7de 100644 --- a/assets/js/types/evcc.ts +++ b/assets/js/types/evcc.ts @@ -375,7 +375,7 @@ export interface Vehicle { minSoc?: number; limitSoc?: number; plan?: StaticPlan; - repeatingPlans: RepeatingPlan[]; + repeatingPlans: RepeatingPlan[] | null; title: string; features?: string[]; capacity?: number; diff --git a/core/site_vehicles.go b/core/site_vehicles.go index 570e0f031..ae79d7c14 100644 --- a/core/site_vehicles.go +++ b/core/site_vehicles.go @@ -19,18 +19,18 @@ type planStruct struct { } type vehicleStruct struct { - Title string `json:"title"` - Icon string `json:"icon,omitempty"` - Capacity float64 `json:"capacity,omitempty"` - Phases int `json:"phases,omitempty"` - MinSoc int `json:"minSoc,omitempty"` - LimitSoc int `json:"limitSoc,omitempty"` - MinCurrent float64 `json:"minCurrent,omitempty"` - MaxCurrent float64 `json:"maxCurrent,omitempty"` - Priority int `json:"priority,omitempty"` - Features []string `json:"features,omitempty"` - Plan *planStruct `json:"plan,omitempty"` - RepeatingPlans []api.RepeatingPlanStruct `json:"repeatingPlans"` + Title string `json:"title"` + Icon string `json:"icon,omitempty"` + Capacity float64 `json:"capacity,omitempty"` + Phases int `json:"phases,omitempty"` + MinSoc int `json:"minSoc,omitempty"` + LimitSoc int `json:"limitSoc,omitempty"` + MinCurrent float64 `json:"minCurrent,omitempty"` + MaxCurrent float64 `json:"maxCurrent,omitempty"` + Priority int `json:"priority,omitempty"` + Features []string `json:"features,omitempty"` + Plan *planStruct `json:"plan,omitempty"` + RepeatingPlans []api.RepeatingPlan `json:"repeatingPlans"` } // publishVehicles returns a list of vehicle titles diff --git a/core/vehicle/adapter.go b/core/vehicle/adapter.go index e94f87b2e..e801c26f5 100644 --- a/core/vehicle/adapter.go +++ b/core/vehicle/adapter.go @@ -110,7 +110,7 @@ func (v *adapter) SetPlanSoc(ts time.Time, precondition time.Duration, soc int) return nil } -func (v *adapter) SetRepeatingPlans(plans []api.RepeatingPlanStruct) error { +func (v *adapter) SetRepeatingPlans(plans []api.RepeatingPlan) error { for _, plan := range plans { for _, day := range plan.Weekdays { if day < 0 || day > 6 { @@ -134,13 +134,12 @@ func (v *adapter) SetRepeatingPlans(plans []api.RepeatingPlanStruct) error { return nil } -func (v *adapter) GetRepeatingPlans() []api.RepeatingPlanStruct { - var plans []api.RepeatingPlanStruct +func (v *adapter) GetRepeatingPlans() []api.RepeatingPlan { + var plans []api.RepeatingPlan - err := settings.Json(v.key()+keys.RepeatingPlans, &plans) - if err == nil { - return plans + if err := settings.Json(v.key()+keys.RepeatingPlans, &plans); err != nil { + return nil } - return []api.RepeatingPlanStruct{} + return plans } diff --git a/core/vehicle/api.go b/core/vehicle/api.go index 31ff62c8c..da134d852 100644 --- a/core/vehicle/api.go +++ b/core/vehicle/api.go @@ -44,9 +44,9 @@ type API interface { SetPlanSoc(time.Time, time.Duration, int) error // GetRepeatingPlans returns every repeating plan - GetRepeatingPlans() []api.RepeatingPlanStruct + GetRepeatingPlans() []api.RepeatingPlan // SetRepeatingPlans stores every repeating plan - SetRepeatingPlans([]api.RepeatingPlanStruct) error + SetRepeatingPlans([]api.RepeatingPlan) error // // GetMinCurrent returns the min charging current // GetMinCurrent() float64 diff --git a/core/vehicle/dummy.go b/core/vehicle/dummy.go index 98d53cad9..a648d7830 100644 --- a/core/vehicle/dummy.go +++ b/core/vehicle/dummy.go @@ -49,10 +49,10 @@ func (v *dummy) SetPlanSoc(ts time.Time, precondition time.Duration, soc int) er } // SetRepeatingPlans stores every repeating plan -func (v *dummy) SetRepeatingPlans(plans []api.RepeatingPlanStruct) error { +func (v *dummy) SetRepeatingPlans(plans []api.RepeatingPlan) error { return nil } -func (v *dummy) GetRepeatingPlans() []api.RepeatingPlanStruct { - return []api.RepeatingPlanStruct{} +func (v *dummy) GetRepeatingPlans() []api.RepeatingPlan { + return nil } diff --git a/core/vehicle/mock.go b/core/vehicle/mock.go index fed22c4ad..120335104 100644 --- a/core/vehicle/mock.go +++ b/core/vehicle/mock.go @@ -86,10 +86,10 @@ func (mr *MockAPIMockRecorder) GetPlanSoc() *gomock.Call { } // GetRepeatingPlans mocks base method. -func (m *MockAPI) GetRepeatingPlans() []api.RepeatingPlanStruct { +func (m *MockAPI) GetRepeatingPlans() []api.RepeatingPlan { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetRepeatingPlans") - ret0, _ := ret[0].([]api.RepeatingPlanStruct) + ret0, _ := ret[0].([]api.RepeatingPlan) return ret0 } @@ -166,7 +166,7 @@ func (mr *MockAPIMockRecorder) SetPlanSoc(arg0, arg1, arg2 any) *gomock.Call { } // SetRepeatingPlans mocks base method. -func (m *MockAPI) SetRepeatingPlans(arg0 []api.RepeatingPlanStruct) error { +func (m *MockAPI) SetRepeatingPlans(arg0 []api.RepeatingPlan) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetRepeatingPlans", arg0) ret0, _ := ret[0].(error) diff --git a/server/http_vehicle_handler.go b/server/http_vehicle_handler.go index 76f77b9ac..6a2f9169e 100644 --- a/server/http_vehicle_handler.go +++ b/server/http_vehicle_handler.go @@ -131,22 +131,18 @@ func addRepeatingPlansHandler(site site.API) http.HandlerFunc { return } - var plansWrapper struct { - RepeatingPlans []api.RepeatingPlanStruct `json:"plans"` - } - - err = json.NewDecoder(r.Body).Decode(&plansWrapper) - if err != nil { + var res []api.RepeatingPlan + if err := json.NewDecoder(r.Body).Decode(&res); err != nil { jsonError(w, http.StatusBadRequest, err) return } - if err := v.SetRepeatingPlans(plansWrapper.RepeatingPlans); err != nil { + if err := v.SetRepeatingPlans(res); err != nil { jsonError(w, http.StatusBadRequest, err) return } - jsonWrite(w, plansWrapper) + jsonWrite(w, res) } } diff --git a/server/mcp/openapi.json b/server/mcp/openapi.json index 1d664bddc..546342414 100644 --- a/server/mcp/openapi.json +++ b/server/mcp/openapi.json @@ -606,17 +606,6 @@ }, "type": "object" }, - "RepeatingPlans": { - "properties": { - "plans": { - "items": { - "$ref": "#/components/schemas/RepeatingPlan" - }, - "type": "array" - } - }, - "type": "object" - }, "Soc": { "description": "SOC in %", "example": 60, @@ -2310,7 +2299,10 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RepeatingPlans" + "items": { + "$ref": "#/components/schemas/RepeatingPlan" + }, + "type": "array" } } }, @@ -2323,7 +2315,10 @@ "schema": { "properties": { "result": { - "$ref": "#/components/schemas/RepeatingPlans" + "items": { + "$ref": "#/components/schemas/RepeatingPlan" + }, + "type": "array" } }, "type": "object" diff --git a/server/mcp/openapi.md b/server/mcp/openapi.md index c79596473..19754a67b 100644 --- a/server/mcp/openapi.md +++ b/server/mcp/openapi.md @@ -1085,7 +1085,7 @@ Updates the repeating charging plan. | Name | Type | Description | |------|------|-------------| | name | string | Vehicle name | -| requestBody | object | The JSON request body. | +| requestBody | array | The JSON request body. | **Example call:** diff --git a/server/openapi.yaml b/server/openapi.yaml index c5d9ce738..50e62145f 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -988,7 +988,9 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/RepeatingPlans" + type: array + items: + $ref: "#/components/schemas/RepeatingPlan" responses: 200: description: Success @@ -998,7 +1000,9 @@ paths: type: object properties: result: - $ref: "#/components/schemas/RepeatingPlans" + type: array + items: + $ref: "#/components/schemas/RepeatingPlan" /vehicles/{name}/plan/soc: delete: operationId: deleteVehicleSocPlan @@ -1244,13 +1248,6 @@ components: $ref: "#/components/schemas/IANATimeZone" weekdays: $ref: "#/components/schemas/Weekdays" - RepeatingPlans: - type: object - properties: - plans: - type: array - items: - $ref: "#/components/schemas/RepeatingPlan" Soc: description: SOC in % type: number