parent
8d350a7a65
commit
e1accfeb9d
23 changed files with 135 additions and 142 deletions
42
api/plans.go
42
api/plans.go
|
|
@ -1,17 +1,45 @@
|
|||
package api
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
Soc int `json:"soc"` // target soc
|
||||
Active bool `json:"active"` // active flag
|
||||
Precondition int64 `json:"-" todo:"..."` // TODO deprecated
|
||||
Weekdays []int `json:"weekdays"` // 0-6 (Sunday-Saturday)
|
||||
Time string `json:"time"` // HH:MM
|
||||
Tz string `json:"tz"` // timezone in IANA format
|
||||
Soc int `json:"soc"` // target soc
|
||||
Active bool `json:"active"` // active flag
|
||||
}
|
||||
|
||||
type PlanStrategy struct {
|
||||
Continuous bool `json:"continuous"` // force continuous planning
|
||||
Precondition time.Duration `json:"precondition"` // precondition duration in seconds
|
||||
}
|
||||
|
||||
type planStrategy struct {
|
||||
Continuous bool `json:"continuous"` // force continuous planning
|
||||
Precondition int64 `json:"precondition"` // precondition duration in seconds
|
||||
}
|
||||
|
||||
func (ps PlanStrategy) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(planStrategy{
|
||||
Continuous: ps.Continuous,
|
||||
Precondition: int64(ps.Precondition.Seconds()),
|
||||
})
|
||||
}
|
||||
|
||||
func (ps *PlanStrategy) UnmarshalJSON(data []byte) error {
|
||||
var res planStrategy
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*ps = PlanStrategy{
|
||||
Continuous: res.Continuous,
|
||||
Precondition: time.Duration(res.Precondition) * time.Second,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,8 +121,7 @@ export default defineComponent({
|
|||
effectiveLimitSoc: Number,
|
||||
effectivePlanSoc: Number,
|
||||
effectivePlanTime: String,
|
||||
effectivePlanPrecondition: Number,
|
||||
effectivePlanContinuous: Boolean,
|
||||
effectivePlanStrategy: Object as PropType<PlanStrategy>,
|
||||
id: [String, Number],
|
||||
limitEnergy: Number,
|
||||
mode: String,
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ export default defineComponent({
|
|||
weekdays: DEFAULT_WEEKDAYS,
|
||||
time: DEFAULT_TARGET_TIME,
|
||||
soc: DEFAULT_TARGET_SOC,
|
||||
precondition: 0,
|
||||
active: false,
|
||||
tz: this.timezone(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,7 +56,9 @@
|
|||
</div>
|
||||
</h5>
|
||||
<ChargingPlanStrategy
|
||||
v-bind="chargingPlanStrategyProps"
|
||||
:id="id"
|
||||
:precondition="effectivePlanStrategy?.precondition"
|
||||
:continuous="effectivePlanStrategy?.continuous"
|
||||
:disabled="strategyDisabled"
|
||||
:show="strategyOpen"
|
||||
@update="updatePlanStrategy"
|
||||
|
|
@ -107,8 +109,7 @@ export default defineComponent({
|
|||
effectiveLimitSoc: Number,
|
||||
effectivePlanTime: String,
|
||||
effectivePlanSoc: Number,
|
||||
effectivePlanPrecondition: Number,
|
||||
effectivePlanContinuous: Boolean,
|
||||
effectivePlanStrategy: Object as PropType<PlanStrategy>,
|
||||
planEnergy: Number,
|
||||
limitEnergy: Number,
|
||||
socBasedPlanning: Boolean,
|
||||
|
|
@ -159,13 +160,6 @@ export default defineComponent({
|
|||
? { duration, plan, power, rates, targetTime, currency, smartCostType }
|
||||
: null;
|
||||
},
|
||||
chargingPlanStrategyProps(): any {
|
||||
return {
|
||||
id: this.id,
|
||||
precondition: this.effectivePlanPrecondition,
|
||||
continuous: this.effectivePlanContinuous,
|
||||
};
|
||||
},
|
||||
alreadyReached(): boolean {
|
||||
return this.plan.duration === 0;
|
||||
},
|
||||
|
|
@ -186,11 +180,11 @@ export default defineComponent({
|
|||
this.updatePlanDebounced();
|
||||
}
|
||||
},
|
||||
effectivePlanPrecondition() {
|
||||
this.updatePlanDebounced();
|
||||
},
|
||||
effectivePlanContinuous() {
|
||||
this.updatePlanDebounced();
|
||||
effectivePlanStrategy: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.updatePlanDebounced();
|
||||
},
|
||||
},
|
||||
staticPlan: {
|
||||
deep: true,
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ const baseState = {
|
|||
planActive: false,
|
||||
planEnergy: 0,
|
||||
planOverrun: 0,
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: { continuous: false, precondition: 0 },
|
||||
planProjectedEnd: undefined,
|
||||
planProjectedStart: undefined,
|
||||
planTime: undefined,
|
||||
|
|
@ -83,8 +82,10 @@ const baseState = {
|
|||
capacity: 8,
|
||||
features: ["Offline"],
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: false,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vehicle_4",
|
||||
|
|
@ -93,8 +94,10 @@ const baseState = {
|
|||
capacity: 80,
|
||||
features: ["Offline"],
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: true,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
smartCostType: SMART_COST_TYPE.PRICE_FORECAST,
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ import type {
|
|||
Forecast,
|
||||
SMART_COST_TYPE,
|
||||
} from "@/types/evcc";
|
||||
import type { PlanStrategy } from "@/components/ChargingPlans/types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Loadpoint",
|
||||
|
|
@ -189,8 +190,7 @@ export default defineComponent({
|
|||
planTime: String as PropType<string | null>,
|
||||
effectivePlanTime: String as PropType<string | null>,
|
||||
effectivePlanSoc: Number,
|
||||
effectivePlanPrecondition: Number,
|
||||
effectivePlanContinuous: Boolean,
|
||||
effectivePlanStrategy: Object as PropType<PlanStrategy>,
|
||||
vehicleProviderLoggedIn: Boolean,
|
||||
vehicleProviderLoginPath: String,
|
||||
vehicleProviderLogoutPath: String,
|
||||
|
|
|
|||
|
|
@ -48,8 +48,10 @@ const baseArgs = {
|
|||
capacity: 8,
|
||||
features: ["Offline"],
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: false,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vehicle_4",
|
||||
|
|
@ -58,8 +60,10 @@ const baseArgs = {
|
|||
capacity: 80,
|
||||
features: ["Offline"],
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: true,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vehicle_5",
|
||||
|
|
@ -68,8 +72,10 @@ const baseArgs = {
|
|||
capacity: 0.46,
|
||||
features: ["Offline"],
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: false,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
smartCostType: SMART_COST_TYPE.PRICE_FORECAST,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ const baseState = {
|
|||
features: [],
|
||||
name: "",
|
||||
repeatingPlans: [],
|
||||
planPrecondition: 0,
|
||||
planContinuous: false,
|
||||
planStrategy: {
|
||||
continuous: false,
|
||||
precondition: 0,
|
||||
},
|
||||
},
|
||||
enabled: false,
|
||||
connected: true,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ import LimitEnergySelect from "./LimitEnergySelect.vue";
|
|||
import { distanceUnit, distanceValue } from "@/units.ts";
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import { CHARGE_MODE, type Forecast, type Vehicle } from "@/types/evcc";
|
||||
import type { PlanStrategy } from "@/components/ChargingPlans/types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Vehicle",
|
||||
|
|
@ -103,8 +104,7 @@ export default defineComponent({
|
|||
effectiveLimitSoc: Number,
|
||||
effectivePlanSoc: Number,
|
||||
effectivePlanTime: String,
|
||||
effectivePlanPrecondition: Number,
|
||||
effectivePlanContinuous: Boolean,
|
||||
effectivePlanStrategy: Object as PropType<PlanStrategy>,
|
||||
batteryBoostActive: Boolean,
|
||||
enabled: Boolean,
|
||||
heating: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { StaticPlan, RepeatingPlan } from "../components/ChargingPlans/types";
|
||||
import type { StaticPlan, RepeatingPlan, PlanStrategy } from "../components/ChargingPlans/types";
|
||||
import type { ForecastSlot, SolarDetails } from "../components/Forecast/types";
|
||||
|
||||
// react-native-webview
|
||||
|
|
@ -191,7 +191,7 @@ export interface ConfigLoadpoint {
|
|||
smartCostLimit: number | null;
|
||||
planEnergy?: number;
|
||||
planTime?: string;
|
||||
planPrecondition?: number;
|
||||
planStrategy?: PlanStrategy;
|
||||
limitEnergy?: number;
|
||||
limitSoc?: number;
|
||||
circuit?: string;
|
||||
|
|
@ -246,8 +246,7 @@ export interface Loadpoint {
|
|||
effectivePlanId: number;
|
||||
effectivePlanSoc: number;
|
||||
effectivePlanTime: string | null;
|
||||
effectivePlanPrecondition: number;
|
||||
effectivePlanContinuous: boolean;
|
||||
effectivePlanStrategy: PlanStrategy;
|
||||
effectivePriority: number;
|
||||
enableDelay: number;
|
||||
enableThreshold: number;
|
||||
|
|
@ -265,8 +264,7 @@ export interface Loadpoint {
|
|||
planActive: boolean;
|
||||
planEnergy: number;
|
||||
planOverrun: number;
|
||||
planPrecondition: number;
|
||||
planContinuous: boolean;
|
||||
planStrategy: PlanStrategy;
|
||||
planProjectedEnd: string | null;
|
||||
planProjectedStart: string | null;
|
||||
planTime: string | null;
|
||||
|
|
@ -504,8 +502,7 @@ export interface Vehicle {
|
|||
limitSoc?: number;
|
||||
plan?: StaticPlan;
|
||||
repeatingPlans: RepeatingPlan[] | null;
|
||||
planPrecondition: number;
|
||||
planContinuous: boolean;
|
||||
planStrategy: PlanStrategy;
|
||||
title: string;
|
||||
features?: string[];
|
||||
capacity?: number;
|
||||
|
|
|
|||
|
|
@ -58,10 +58,8 @@ const (
|
|||
EffectiveMinCurrent = "effectiveMinCurrent" // effective min current
|
||||
EffectiveMaxCurrent = "effectiveMaxCurrent" // effective max current
|
||||
|
||||
EffectiveLimitSoc = "effectiveLimitSoc" // effective limit soc
|
||||
EffectivePlanStrategy = "effectivePlanStrategy" // effective plan strategy (deprecated, use individual fields)
|
||||
EffectivePlanPrecondition = "effectivePlanPrecondition" // effective plan precondition duration
|
||||
EffectivePlanContinuous = "effectivePlanContinuous" // effective plan continuous planning
|
||||
EffectiveLimitSoc = "effectiveLimitSoc" // effective limit soc
|
||||
EffectivePlanStrategy = "effectivePlanStrategy" // effective plan strategy
|
||||
|
||||
// measurements
|
||||
ChargePower = "chargePower" // charge power
|
||||
|
|
@ -86,8 +84,6 @@ const (
|
|||
PlanProjectedEnd = "planProjectedEnd" // charge plan ends (end of last slot)
|
||||
PlanOverrun = "planOverrun" // charge plan goal not reachable in time
|
||||
PlanStrategy = "planStrategy" // charge plan strategy (precondition, continuous)
|
||||
PlanPrecondition = "planPrecondition" // charge plan precondition duration
|
||||
PlanContinuous = "planContinuous" // charge plan continuous planning
|
||||
|
||||
// repeating plans
|
||||
RepeatingPlans = "repeatingPlans" // key to access all repeating plans in db
|
||||
|
|
|
|||
|
|
@ -690,8 +690,7 @@ func (lp *Loadpoint) Prepare(site site.API, uiChan chan<- util.Param, pushChan c
|
|||
// restored settings
|
||||
lp.publish(keys.PlanTime, lp.planTime)
|
||||
lp.publish(keys.PlanEnergy, lp.planEnergy)
|
||||
lp.publish(keys.PlanPrecondition, int64(lp.planStrategy.Precondition.Seconds()))
|
||||
lp.publish(keys.PlanContinuous, lp.planStrategy.Continuous)
|
||||
lp.publish(keys.PlanStrategy, lp.planStrategy)
|
||||
lp.publish(keys.LimitSoc, lp.limitSoc)
|
||||
lp.publish(keys.LimitEnergy, lp.limitEnergy)
|
||||
|
||||
|
|
|
|||
|
|
@ -405,8 +405,9 @@ func (lp *Loadpoint) setPlanStrategy(strategy api.PlanStrategy) error {
|
|||
}
|
||||
|
||||
lp.planStrategy = strategy
|
||||
lp.publish(keys.PlanPrecondition, int64(strategy.Precondition.Seconds()))
|
||||
lp.publish(keys.PlanContinuous, strategy.Continuous)
|
||||
lp.publish(keys.PlanStrategy, strategy)
|
||||
|
||||
lp.publish(keys.EffectivePlanStrategy, lp.getEffectivePlanStrategy())
|
||||
|
||||
lp.requestUpdate()
|
||||
|
||||
|
|
|
|||
|
|
@ -12,16 +12,14 @@ import (
|
|||
|
||||
// PublishEffectiveValues publishes all effective values
|
||||
func (lp *Loadpoint) PublishEffectiveValues() {
|
||||
strategy := lp.EffectivePlanStrategy()
|
||||
lp.publish(keys.EffectivePriority, lp.EffectivePriority())
|
||||
lp.publish(keys.EffectivePlanId, lp.EffectivePlanId())
|
||||
lp.publish(keys.EffectivePlanTime, lp.EffectivePlanTime())
|
||||
lp.publish(keys.EffectivePlanSoc, lp.EffectivePlanSoc())
|
||||
lp.publish(keys.EffectivePlanStrategy, lp.EffectivePlanStrategy())
|
||||
lp.publish(keys.EffectiveMinCurrent, lp.effectiveMinCurrent())
|
||||
lp.publish(keys.EffectiveMaxCurrent, lp.effectiveMaxCurrent())
|
||||
lp.publish(keys.EffectiveLimitSoc, lp.EffectiveLimitSoc())
|
||||
lp.publish(keys.EffectivePlanPrecondition, int64(strategy.Precondition.Seconds()))
|
||||
lp.publish(keys.EffectivePlanContinuous, strategy.Continuous)
|
||||
}
|
||||
|
||||
// EffectivePriority returns the effective priority
|
||||
|
|
|
|||
|
|
@ -13,27 +13,24 @@ import (
|
|||
)
|
||||
|
||||
type planStruct struct {
|
||||
Soc int `json:"soc"`
|
||||
Continuous bool `json:"continuous"`
|
||||
Precondition int64 `json:"precondition"`
|
||||
Time time.Time `json:"time"`
|
||||
Soc int `json:"soc"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
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.RepeatingPlan `json:"repeatingPlans"`
|
||||
PlanPrecondition int64 `json:"planPrecondition"`
|
||||
PlanContinuous bool `json:"planContinuous"`
|
||||
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"`
|
||||
PlanStrategy api.PlanStrategy `json:"planStrategy"`
|
||||
}
|
||||
|
||||
// publishVehicles returns a list of vehicle titles
|
||||
|
|
@ -48,32 +45,34 @@ func (site *Site) publishVehicles() {
|
|||
}
|
||||
|
||||
ac := instance.OnIdentified()
|
||||
strategy := v.GetPlanStrategy()
|
||||
|
||||
var plan *planStruct
|
||||
if time, soc := v.GetPlanSoc(); !time.IsZero() {
|
||||
plan = &planStruct{Soc: soc, Precondition: int64(strategy.Precondition.Seconds()), Time: time}
|
||||
plan = &planStruct{
|
||||
Soc: soc,
|
||||
Time: time,
|
||||
}
|
||||
}
|
||||
|
||||
res[v.Name()] = vehicleStruct{
|
||||
Title: instance.GetTitle(),
|
||||
Icon: instance.Icon(),
|
||||
Capacity: instance.Capacity(),
|
||||
Phases: instance.Phases(),
|
||||
MinSoc: v.GetMinSoc(),
|
||||
LimitSoc: v.GetLimitSoc(),
|
||||
MinCurrent: ac.MinCurrent,
|
||||
MaxCurrent: ac.MaxCurrent,
|
||||
Priority: ac.Priority,
|
||||
Features: lo.Map(instance.Features(), func(f api.Feature, _ int) string { return f.String() }),
|
||||
Plan: plan,
|
||||
RepeatingPlans: v.GetRepeatingPlans(),
|
||||
PlanPrecondition: int64(strategy.Precondition.Seconds()),
|
||||
PlanContinuous: strategy.Continuous,
|
||||
Title: instance.GetTitle(),
|
||||
Icon: instance.Icon(),
|
||||
Capacity: instance.Capacity(),
|
||||
Phases: instance.Phases(),
|
||||
MinSoc: v.GetMinSoc(),
|
||||
LimitSoc: v.GetLimitSoc(),
|
||||
MinCurrent: ac.MinCurrent,
|
||||
MaxCurrent: ac.MaxCurrent,
|
||||
Priority: ac.Priority,
|
||||
Features: lo.Map(instance.Features(), func(f api.Feature, _ int) string { return f.String() }),
|
||||
Plan: plan,
|
||||
RepeatingPlans: v.GetRepeatingPlans(),
|
||||
PlanStrategy: v.GetPlanStrategy(),
|
||||
}
|
||||
|
||||
// publish effective plan strategy immediately for soc-based planning
|
||||
if lp := site.coordinator.Owner(instance); lp != nil {
|
||||
go lp.PublishEffectiveValues()
|
||||
lp.PublishEffectiveValues()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ func (v *adapter) SetPlanStrategy(planStrategy api.PlanStrategy) error {
|
|||
return err
|
||||
}
|
||||
|
||||
v.log.DEBUG.Printf("update plan strategy for vehicle %s (precondition: %vs, continuous: %v)", v.name, planStrategy.Continuous, planStrategy.Precondition)
|
||||
v.publish()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ type PlanPreviewResponse struct {
|
|||
Duration int64 `json:"duration"`
|
||||
Plan api.Rates `json:"plan"`
|
||||
Power float64 `json:"power"`
|
||||
|
||||
// TODO remove
|
||||
Continuous bool `json:"continuous"`
|
||||
Precondition int64 `json:"precondition"`
|
||||
}
|
||||
|
||||
// planHandler returns the current plan
|
||||
|
|
@ -100,10 +96,6 @@ func staticPlanPreviewHandler(lp loadpoint.API) http.HandlerFunc {
|
|||
Duration: int64(requiredDuration.Seconds()),
|
||||
Plan: plan,
|
||||
Power: maxPower,
|
||||
|
||||
// TODO remove
|
||||
Continuous: strategy.Continuous,
|
||||
Precondition: int64(strategy.Precondition.Seconds()),
|
||||
}
|
||||
|
||||
jsonWrite(w, res)
|
||||
|
|
@ -206,7 +198,7 @@ func planStrategyHandler(lp loadpoint.API) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
res := planStrategyPayloadFromApi(lp.GetPlanStrategy())
|
||||
res := lp.GetPlanStrategy()
|
||||
|
||||
jsonWrite(w, res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,14 +112,12 @@ func planSocHandler(site site.API) http.HandlerFunc {
|
|||
}
|
||||
|
||||
func planStrategyHandlerSetter(r *http.Request, set func(api.PlanStrategy) error) error {
|
||||
var planStrategy planStrategyPayload
|
||||
if err := json.NewDecoder(r.Body).Decode(&planStrategy); err != nil {
|
||||
var res api.PlanStrategy
|
||||
if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
|
||||
return err
|
||||
}
|
||||
return set(api.PlanStrategy{
|
||||
Continuous: planStrategy.Continuous,
|
||||
Precondition: time.Duration(planStrategy.Precondition) * time.Second,
|
||||
})
|
||||
|
||||
return set(res)
|
||||
}
|
||||
|
||||
// updatePlanStrategyHandler updates plan strategy
|
||||
|
|
@ -137,7 +135,7 @@ func updatePlanStrategyHandler(site site.API) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
res := planStrategyPayloadFromApi(v.GetPlanStrategy())
|
||||
res := v.GetPlanStrategy()
|
||||
|
||||
jsonWrite(w, res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,15 +68,12 @@ func durationSetter(set func(time.Duration) error) func(string) error {
|
|||
|
||||
func planStrategySetter(set func(api.PlanStrategy) error) func(string) error {
|
||||
return func(payload string) error {
|
||||
var planStrategy planStrategyPayload
|
||||
if err := json.Unmarshal([]byte(payload), &planStrategy); err != nil {
|
||||
var res api.PlanStrategy
|
||||
if err := json.Unmarshal([]byte(payload), &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return set(api.PlanStrategy{
|
||||
Continuous: planStrategy.Continuous,
|
||||
Precondition: time.Duration(planStrategy.Precondition) * time.Second,
|
||||
})
|
||||
return set(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,22 +2,8 @@ package server
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
type planStrategyPayload struct {
|
||||
Continuous bool `json:"continuous"`
|
||||
Precondition int64 `json:"precondition"`
|
||||
}
|
||||
|
||||
func planStrategyPayloadFromApi(ps api.PlanStrategy) planStrategyPayload {
|
||||
return planStrategyPayload{
|
||||
Continuous: ps.Continuous,
|
||||
Precondition: int64(ps.Precondition.Seconds()),
|
||||
}
|
||||
}
|
||||
|
||||
type planGoal[T any] struct {
|
||||
Time time.Time `json:"time"`
|
||||
Value T `json:"value"`
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ func (d *Duration) Duration() time.Duration {
|
|||
return time.Duration(*d)
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
val, err := iso8601.ParseDuration(string(b))
|
||||
func (d *Duration) UnmarshalJSON(data []byte) error {
|
||||
val, err := iso8601.ParseDuration(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ type Timestamp struct {
|
|||
// Layout is the time.Parse compliant parsing string for use when parsing Shortened RFC-3339 compliant timestamps.
|
||||
const Layout = "2006-01-02T15:04Z"
|
||||
|
||||
func (ct *Timestamp) UnmarshalJSON(b []byte) (err error) {
|
||||
s := strings.Trim(string(b), "\"")
|
||||
func (ct *Timestamp) UnmarshalJSON(data []byte) (err error) {
|
||||
s := strings.Trim(string(data), "\"")
|
||||
if s == "null" {
|
||||
ct.Time = time.Time{}
|
||||
return
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ type Duration struct {
|
|||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
func (d *Duration) UnmarshalJSON(data []byte) error {
|
||||
var v any
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue