Planner: drop deprecated publishing keys #2 (BC) (#26540)

This commit is contained in:
Ingo 2026-02-01 19:38:19 +01:00 • committed by GitHub
parent 8d350a7a65
commit e1accfeb9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 135 additions and 142 deletions

View file

@ -1,17 +1,45 @@
package api package api
import "time" import (
"encoding/json"
"time"
)
type RepeatingPlan struct { type RepeatingPlan struct {
Weekdays []int `json:"weekdays"` // 0-6 (Sunday-Saturday) Weekdays []int `json:"weekdays"` // 0-6 (Sunday-Saturday)
Time string `json:"time"` // HH:MM Time string `json:"time"` // HH:MM
Tz string `json:"tz"` // timezone in IANA format Tz string `json:"tz"` // timezone in IANA format
Soc int `json:"soc"` // target soc Soc int `json:"soc"` // target soc
Active bool `json:"active"` // active flag Active bool `json:"active"` // active flag
Precondition int64 `json:"-" todo:"..."` // TODO deprecated
} }
type PlanStrategy struct { type PlanStrategy struct {
Continuous bool `json:"continuous"` // force continuous planning Continuous bool `json:"continuous"` // force continuous planning
Precondition time.Duration `json:"precondition"` // precondition duration in seconds 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
}

View file

@ -121,8 +121,7 @@ export default defineComponent({
effectiveLimitSoc: Number, effectiveLimitSoc: Number,
effectivePlanSoc: Number, effectivePlanSoc: Number,
effectivePlanTime: String, effectivePlanTime: String,
effectivePlanPrecondition: Number, effectivePlanStrategy: Object as PropType<PlanStrategy>,
effectivePlanContinuous: Boolean,
id: [String, Number], id: [String, Number],
limitEnergy: Number, limitEnergy: Number,
mode: String, mode: String,

View file

@ -62,7 +62,6 @@ export default defineComponent({
weekdays: DEFAULT_WEEKDAYS, weekdays: DEFAULT_WEEKDAYS,
time: DEFAULT_TARGET_TIME, time: DEFAULT_TARGET_TIME,
soc: DEFAULT_TARGET_SOC, soc: DEFAULT_TARGET_SOC,
precondition: 0,
active: false, active: false,
tz: this.timezone(), tz: this.timezone(),
}; };

View file

@ -56,7 +56,9 @@
</div> </div>
</h5> </h5>
<ChargingPlanStrategy <ChargingPlanStrategy
v-bind="chargingPlanStrategyProps" :id="id"
:precondition="effectivePlanStrategy?.precondition"
:continuous="effectivePlanStrategy?.continuous"
:disabled="strategyDisabled" :disabled="strategyDisabled"
:show="strategyOpen" :show="strategyOpen"
@update="updatePlanStrategy" @update="updatePlanStrategy"
@ -107,8 +109,7 @@ export default defineComponent({
effectiveLimitSoc: Number, effectiveLimitSoc: Number,
effectivePlanTime: String, effectivePlanTime: String,
effectivePlanSoc: Number, effectivePlanSoc: Number,
effectivePlanPrecondition: Number, effectivePlanStrategy: Object as PropType<PlanStrategy>,
effectivePlanContinuous: Boolean,
planEnergy: Number, planEnergy: Number,
limitEnergy: Number, limitEnergy: Number,
socBasedPlanning: Boolean, socBasedPlanning: Boolean,
@ -159,13 +160,6 @@ export default defineComponent({
? { duration, plan, power, rates, targetTime, currency, smartCostType } ? { duration, plan, power, rates, targetTime, currency, smartCostType }
: null; : null;
}, },
chargingPlanStrategyProps(): any {
return {
id: this.id,
precondition: this.effectivePlanPrecondition,
continuous: this.effectivePlanContinuous,
};
},
alreadyReached(): boolean { alreadyReached(): boolean {
return this.plan.duration === 0; return this.plan.duration === 0;
}, },
@ -186,11 +180,11 @@ export default defineComponent({
this.updatePlanDebounced(); this.updatePlanDebounced();
} }
}, },
effectivePlanPrecondition() { effectivePlanStrategy: {
this.updatePlanDebounced(); deep: true,
}, handler() {
effectivePlanContinuous() { this.updatePlanDebounced();
this.updatePlanDebounced(); },
}, },
staticPlan: { staticPlan: {
deep: true, deep: true,

View file

@ -51,8 +51,7 @@ const baseState = {
planActive: false, planActive: false,
planEnergy: 0, planEnergy: 0,
planOverrun: 0, planOverrun: 0,
planPrecondition: 0, planStrategy: { continuous: false, precondition: 0 },
planContinuous: false,
planProjectedEnd: undefined, planProjectedEnd: undefined,
planProjectedStart: undefined, planProjectedStart: undefined,
planTime: undefined, planTime: undefined,
@ -83,8 +82,10 @@ const baseState = {
capacity: 8, capacity: 8,
features: ["Offline"], features: ["Offline"],
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: false,
precondition: 0,
},
}, },
{ {
name: "vehicle_4", name: "vehicle_4",
@ -93,8 +94,10 @@ const baseState = {
capacity: 80, capacity: 80,
features: ["Offline"], features: ["Offline"],
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: true,
precondition: 0,
},
}, },
], ],
smartCostType: SMART_COST_TYPE.PRICE_FORECAST, smartCostType: SMART_COST_TYPE.PRICE_FORECAST,

View file

@ -127,6 +127,7 @@ import type {
Forecast, Forecast,
SMART_COST_TYPE, SMART_COST_TYPE,
} from "@/types/evcc"; } from "@/types/evcc";
import type { PlanStrategy } from "@/components/ChargingPlans/types";
export default defineComponent({ export default defineComponent({
name: "Loadpoint", name: "Loadpoint",
@ -189,8 +190,7 @@ export default defineComponent({
planTime: String as PropType<string | null>, planTime: String as PropType<string | null>,
effectivePlanTime: String as PropType<string | null>, effectivePlanTime: String as PropType<string | null>,
effectivePlanSoc: Number, effectivePlanSoc: Number,
effectivePlanPrecondition: Number, effectivePlanStrategy: Object as PropType<PlanStrategy>,
effectivePlanContinuous: Boolean,
vehicleProviderLoggedIn: Boolean, vehicleProviderLoggedIn: Boolean,
vehicleProviderLoginPath: String, vehicleProviderLoginPath: String,
vehicleProviderLogoutPath: String, vehicleProviderLogoutPath: String,

View file

@ -48,8 +48,10 @@ const baseArgs = {
capacity: 8, capacity: 8,
features: ["Offline"], features: ["Offline"],
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: false,
precondition: 0,
},
}, },
{ {
name: "vehicle_4", name: "vehicle_4",
@ -58,8 +60,10 @@ const baseArgs = {
capacity: 80, capacity: 80,
features: ["Offline"], features: ["Offline"],
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: true,
precondition: 0,
},
}, },
{ {
name: "vehicle_5", name: "vehicle_5",
@ -68,8 +72,10 @@ const baseArgs = {
capacity: 0.46, capacity: 0.46,
features: ["Offline"], features: ["Offline"],
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: false,
precondition: 0,
},
}, },
], ],
smartCostType: SMART_COST_TYPE.PRICE_FORECAST, smartCostType: SMART_COST_TYPE.PRICE_FORECAST,

View file

@ -10,8 +10,10 @@ const baseState = {
features: [], features: [],
name: "", name: "",
repeatingPlans: [], repeatingPlans: [],
planPrecondition: 0, planStrategy: {
planContinuous: false, continuous: false,
precondition: 0,
},
}, },
enabled: false, enabled: false,
connected: true, connected: true,

View file

@ -80,6 +80,7 @@ import LimitEnergySelect from "./LimitEnergySelect.vue";
import { distanceUnit, distanceValue } from "@/units.ts"; import { distanceUnit, distanceValue } from "@/units.ts";
import { defineComponent, type PropType } from "vue"; import { defineComponent, type PropType } from "vue";
import { CHARGE_MODE, type Forecast, type Vehicle } from "@/types/evcc"; import { CHARGE_MODE, type Forecast, type Vehicle } from "@/types/evcc";
import type { PlanStrategy } from "@/components/ChargingPlans/types";
export default defineComponent({ export default defineComponent({
name: "Vehicle", name: "Vehicle",
@ -103,8 +104,7 @@ export default defineComponent({
effectiveLimitSoc: Number, effectiveLimitSoc: Number,
effectivePlanSoc: Number, effectivePlanSoc: Number,
effectivePlanTime: String, effectivePlanTime: String,
effectivePlanPrecondition: Number, effectivePlanStrategy: Object as PropType<PlanStrategy>,
effectivePlanContinuous: Boolean,
batteryBoostActive: Boolean, batteryBoostActive: Boolean,
enabled: Boolean, enabled: Boolean,
heating: Boolean, heating: Boolean,

View file

@ -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"; import type { ForecastSlot, SolarDetails } from "../components/Forecast/types";
// react-native-webview // react-native-webview
@ -191,7 +191,7 @@ export interface ConfigLoadpoint {
smartCostLimit: number | null; smartCostLimit: number | null;
planEnergy?: number; planEnergy?: number;
planTime?: string; planTime?: string;
planPrecondition?: number; planStrategy?: PlanStrategy;
limitEnergy?: number; limitEnergy?: number;
limitSoc?: number; limitSoc?: number;
circuit?: string; circuit?: string;
@ -246,8 +246,7 @@ export interface Loadpoint {
effectivePlanId: number; effectivePlanId: number;
effectivePlanSoc: number; effectivePlanSoc: number;
effectivePlanTime: string | null; effectivePlanTime: string | null;
effectivePlanPrecondition: number; effectivePlanStrategy: PlanStrategy;
effectivePlanContinuous: boolean;
effectivePriority: number; effectivePriority: number;
enableDelay: number; enableDelay: number;
enableThreshold: number; enableThreshold: number;
@ -265,8 +264,7 @@ export interface Loadpoint {
planActive: boolean; planActive: boolean;
planEnergy: number; planEnergy: number;
planOverrun: number; planOverrun: number;
planPrecondition: number; planStrategy: PlanStrategy;
planContinuous: boolean;
planProjectedEnd: string | null; planProjectedEnd: string | null;
planProjectedStart: string | null; planProjectedStart: string | null;
planTime: string | null; planTime: string | null;
@ -504,8 +502,7 @@ export interface Vehicle {
limitSoc?: number; limitSoc?: number;
plan?: StaticPlan; plan?: StaticPlan;
repeatingPlans: RepeatingPlan[] | null; repeatingPlans: RepeatingPlan[] | null;
planPrecondition: number; planStrategy: PlanStrategy;
planContinuous: boolean;
title: string; title: string;
features?: string[]; features?: string[];
capacity?: number; capacity?: number;

View file

@ -58,10 +58,8 @@ const (
EffectiveMinCurrent = "effectiveMinCurrent" // effective min current EffectiveMinCurrent = "effectiveMinCurrent" // effective min current
EffectiveMaxCurrent = "effectiveMaxCurrent" // effective max current EffectiveMaxCurrent = "effectiveMaxCurrent" // effective max current
EffectiveLimitSoc = "effectiveLimitSoc" // effective limit soc EffectiveLimitSoc = "effectiveLimitSoc" // effective limit soc
EffectivePlanStrategy = "effectivePlanStrategy" // effective plan strategy (deprecated, use individual fields) EffectivePlanStrategy = "effectivePlanStrategy" // effective plan strategy
EffectivePlanPrecondition = "effectivePlanPrecondition" // effective plan precondition duration
EffectivePlanContinuous = "effectivePlanContinuous" // effective plan continuous planning
// measurements // measurements
ChargePower = "chargePower" // charge power ChargePower = "chargePower" // charge power
@ -86,8 +84,6 @@ const (
PlanProjectedEnd = "planProjectedEnd" // charge plan ends (end of last slot) PlanProjectedEnd = "planProjectedEnd" // charge plan ends (end of last slot)
PlanOverrun = "planOverrun" // charge plan goal not reachable in time PlanOverrun = "planOverrun" // charge plan goal not reachable in time
PlanStrategy = "planStrategy" // charge plan strategy (precondition, continuous) PlanStrategy = "planStrategy" // charge plan strategy (precondition, continuous)
PlanPrecondition = "planPrecondition" // charge plan precondition duration
PlanContinuous = "planContinuous" // charge plan continuous planning
// repeating plans // repeating plans
RepeatingPlans = "repeatingPlans" // key to access all repeating plans in db RepeatingPlans = "repeatingPlans" // key to access all repeating plans in db

View file

@ -690,8 +690,7 @@ func (lp *Loadpoint) Prepare(site site.API, uiChan chan<- util.Param, pushChan c
// restored settings // restored settings
lp.publish(keys.PlanTime, lp.planTime) lp.publish(keys.PlanTime, lp.planTime)
lp.publish(keys.PlanEnergy, lp.planEnergy) lp.publish(keys.PlanEnergy, lp.planEnergy)
lp.publish(keys.PlanPrecondition, int64(lp.planStrategy.Precondition.Seconds())) lp.publish(keys.PlanStrategy, lp.planStrategy)
lp.publish(keys.PlanContinuous, lp.planStrategy.Continuous)
lp.publish(keys.LimitSoc, lp.limitSoc) lp.publish(keys.LimitSoc, lp.limitSoc)
lp.publish(keys.LimitEnergy, lp.limitEnergy) lp.publish(keys.LimitEnergy, lp.limitEnergy)

View file

@ -405,8 +405,9 @@ func (lp *Loadpoint) setPlanStrategy(strategy api.PlanStrategy) error {
} }
lp.planStrategy = strategy lp.planStrategy = strategy
lp.publish(keys.PlanPrecondition, int64(strategy.Precondition.Seconds())) lp.publish(keys.PlanStrategy, strategy)
lp.publish(keys.PlanContinuous, strategy.Continuous)
lp.publish(keys.EffectivePlanStrategy, lp.getEffectivePlanStrategy())
lp.requestUpdate() lp.requestUpdate()

View file

@ -12,16 +12,14 @@ import (
// PublishEffectiveValues publishes all effective values // PublishEffectiveValues publishes all effective values
func (lp *Loadpoint) PublishEffectiveValues() { func (lp *Loadpoint) PublishEffectiveValues() {
strategy := lp.EffectivePlanStrategy()
lp.publish(keys.EffectivePriority, lp.EffectivePriority()) lp.publish(keys.EffectivePriority, lp.EffectivePriority())
lp.publish(keys.EffectivePlanId, lp.EffectivePlanId()) lp.publish(keys.EffectivePlanId, lp.EffectivePlanId())
lp.publish(keys.EffectivePlanTime, lp.EffectivePlanTime()) lp.publish(keys.EffectivePlanTime, lp.EffectivePlanTime())
lp.publish(keys.EffectivePlanSoc, lp.EffectivePlanSoc()) lp.publish(keys.EffectivePlanSoc, lp.EffectivePlanSoc())
lp.publish(keys.EffectivePlanStrategy, lp.EffectivePlanStrategy())
lp.publish(keys.EffectiveMinCurrent, lp.effectiveMinCurrent()) lp.publish(keys.EffectiveMinCurrent, lp.effectiveMinCurrent())
lp.publish(keys.EffectiveMaxCurrent, lp.effectiveMaxCurrent()) lp.publish(keys.EffectiveMaxCurrent, lp.effectiveMaxCurrent())
lp.publish(keys.EffectiveLimitSoc, lp.EffectiveLimitSoc()) 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 // EffectivePriority returns the effective priority

View file

@ -13,27 +13,24 @@ import (
) )
type planStruct struct { type planStruct struct {
Soc int `json:"soc"` Soc int `json:"soc"`
Continuous bool `json:"continuous"` Time time.Time `json:"time"`
Precondition int64 `json:"precondition"`
Time time.Time `json:"time"`
} }
type vehicleStruct struct { type vehicleStruct struct {
Title string `json:"title"` Title string `json:"title"`
Icon string `json:"icon,omitempty"` Icon string `json:"icon,omitempty"`
Capacity float64 `json:"capacity,omitempty"` Capacity float64 `json:"capacity,omitempty"`
Phases int `json:"phases,omitempty"` Phases int `json:"phases,omitempty"`
MinSoc int `json:"minSoc,omitempty"` MinSoc int `json:"minSoc,omitempty"`
LimitSoc int `json:"limitSoc,omitempty"` LimitSoc int `json:"limitSoc,omitempty"`
MinCurrent float64 `json:"minCurrent,omitempty"` MinCurrent float64 `json:"minCurrent,omitempty"`
MaxCurrent float64 `json:"maxCurrent,omitempty"` MaxCurrent float64 `json:"maxCurrent,omitempty"`
Priority int `json:"priority,omitempty"` Priority int `json:"priority,omitempty"`
Features []string `json:"features,omitempty"` Features []string `json:"features,omitempty"`
Plan *planStruct `json:"plan,omitempty"` Plan *planStruct `json:"plan,omitempty"`
RepeatingPlans []api.RepeatingPlan `json:"repeatingPlans"` RepeatingPlans []api.RepeatingPlan `json:"repeatingPlans"`
PlanPrecondition int64 `json:"planPrecondition"` PlanStrategy api.PlanStrategy `json:"planStrategy"`
PlanContinuous bool `json:"planContinuous"`
} }
// publishVehicles returns a list of vehicle titles // publishVehicles returns a list of vehicle titles
@ -48,32 +45,34 @@ func (site *Site) publishVehicles() {
} }
ac := instance.OnIdentified() ac := instance.OnIdentified()
strategy := v.GetPlanStrategy()
var plan *planStruct var plan *planStruct
if time, soc := v.GetPlanSoc(); !time.IsZero() { 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{ res[v.Name()] = vehicleStruct{
Title: instance.GetTitle(), Title: instance.GetTitle(),
Icon: instance.Icon(), Icon: instance.Icon(),
Capacity: instance.Capacity(), Capacity: instance.Capacity(),
Phases: instance.Phases(), Phases: instance.Phases(),
MinSoc: v.GetMinSoc(), MinSoc: v.GetMinSoc(),
LimitSoc: v.GetLimitSoc(), LimitSoc: v.GetLimitSoc(),
MinCurrent: ac.MinCurrent, MinCurrent: ac.MinCurrent,
MaxCurrent: ac.MaxCurrent, MaxCurrent: ac.MaxCurrent,
Priority: ac.Priority, Priority: ac.Priority,
Features: lo.Map(instance.Features(), func(f api.Feature, _ int) string { return f.String() }), Features: lo.Map(instance.Features(), func(f api.Feature, _ int) string { return f.String() }),
Plan: plan, Plan: plan,
RepeatingPlans: v.GetRepeatingPlans(), RepeatingPlans: v.GetRepeatingPlans(),
PlanPrecondition: int64(strategy.Precondition.Seconds()), PlanStrategy: v.GetPlanStrategy(),
PlanContinuous: strategy.Continuous,
} }
// publish effective plan strategy immediately for soc-based planning
if lp := site.coordinator.Owner(instance); lp != nil { if lp := site.coordinator.Owner(instance); lp != nil {
go lp.PublishEffectiveValues() lp.PublishEffectiveValues()
} }
} }

View file

@ -169,7 +169,6 @@ func (v *adapter) SetPlanStrategy(planStrategy api.PlanStrategy) error {
return err return err
} }
v.log.DEBUG.Printf("update plan strategy for vehicle %s (precondition: %vs, continuous: %v)", v.name, planStrategy.Continuous, planStrategy.Precondition)
v.publish() v.publish()
return nil return nil

View file

@ -26,10 +26,6 @@ type PlanPreviewResponse struct {
Duration int64 `json:"duration"` Duration int64 `json:"duration"`
Plan api.Rates `json:"plan"` Plan api.Rates `json:"plan"`
Power float64 `json:"power"` Power float64 `json:"power"`
// TODO remove
Continuous bool `json:"continuous"`
Precondition int64 `json:"precondition"`
} }
// planHandler returns the current plan // planHandler returns the current plan
@ -100,10 +96,6 @@ func staticPlanPreviewHandler(lp loadpoint.API) http.HandlerFunc {
Duration: int64(requiredDuration.Seconds()), Duration: int64(requiredDuration.Seconds()),
Plan: plan, Plan: plan,
Power: maxPower, Power: maxPower,
// TODO remove
Continuous: strategy.Continuous,
Precondition: int64(strategy.Precondition.Seconds()),
} }
jsonWrite(w, res) jsonWrite(w, res)
@ -206,7 +198,7 @@ func planStrategyHandler(lp loadpoint.API) http.HandlerFunc {
return return
} }
res := planStrategyPayloadFromApi(lp.GetPlanStrategy()) res := lp.GetPlanStrategy()
jsonWrite(w, res) jsonWrite(w, res)
} }

View file

@ -112,14 +112,12 @@ func planSocHandler(site site.API) http.HandlerFunc {
} }
func planStrategyHandlerSetter(r *http.Request, set func(api.PlanStrategy) error) error { func planStrategyHandlerSetter(r *http.Request, set func(api.PlanStrategy) error) error {
var planStrategy planStrategyPayload var res api.PlanStrategy
if err := json.NewDecoder(r.Body).Decode(&planStrategy); err != nil { if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
return err return err
} }
return set(api.PlanStrategy{
Continuous: planStrategy.Continuous, return set(res)
Precondition: time.Duration(planStrategy.Precondition) * time.Second,
})
} }
// updatePlanStrategyHandler updates plan strategy // updatePlanStrategyHandler updates plan strategy
@ -137,7 +135,7 @@ func updatePlanStrategyHandler(site site.API) http.HandlerFunc {
return return
} }
res := planStrategyPayloadFromApi(v.GetPlanStrategy()) res := v.GetPlanStrategy()
jsonWrite(w, res) jsonWrite(w, res)
} }

View file

@ -68,15 +68,12 @@ func durationSetter(set func(time.Duration) error) func(string) error {
func planStrategySetter(set func(api.PlanStrategy) error) func(string) error { func planStrategySetter(set func(api.PlanStrategy) error) func(string) error {
return func(payload string) error { return func(payload string) error {
var planStrategy planStrategyPayload var res api.PlanStrategy
if err := json.Unmarshal([]byte(payload), &planStrategy); err != nil { if err := json.Unmarshal([]byte(payload), &res); err != nil {
return err return err
} }
return set(api.PlanStrategy{ return set(res)
Continuous: planStrategy.Continuous,
Precondition: time.Duration(planStrategy.Precondition) * time.Second,
})
} }
} }

View file

@ -2,22 +2,8 @@ package server
import ( import (
"time" "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 { type planGoal[T any] struct {
Time time.Time `json:"time"` Time time.Time `json:"time"`
Value T `json:"value"` Value T `json:"value"`

View file

@ -24,8 +24,8 @@ func (d *Duration) Duration() time.Duration {
return time.Duration(*d) return time.Duration(*d)
} }
func (d *Duration) UnmarshalJSON(b []byte) error { func (d *Duration) UnmarshalJSON(data []byte) error {
val, err := iso8601.ParseDuration(string(b)) val, err := iso8601.ParseDuration(string(data))
if err != nil { if err != nil {
return err return err
} }

View file

@ -15,8 +15,8 @@ type Timestamp struct {
// Layout is the time.Parse compliant parsing string for use when parsing Shortened RFC-3339 compliant timestamps. // Layout is the time.Parse compliant parsing string for use when parsing Shortened RFC-3339 compliant timestamps.
const Layout = "2006-01-02T15:04Z" const Layout = "2006-01-02T15:04Z"
func (ct *Timestamp) UnmarshalJSON(b []byte) (err error) { func (ct *Timestamp) UnmarshalJSON(data []byte) (err error) {
s := strings.Trim(string(b), "\"") s := strings.Trim(string(data), "\"")
if s == "null" { if s == "null" {
ct.Time = time.Time{} ct.Time = time.Time{}
return return

View file

@ -14,9 +14,9 @@ type Duration struct {
} }
// UnmarshalJSON implements json.Unmarshaler // UnmarshalJSON implements json.Unmarshaler
func (d *Duration) UnmarshalJSON(b []byte) error { func (d *Duration) UnmarshalJSON(data []byte) error {
var v any var v any
if err := json.Unmarshal(b, &v); err != nil { if err := json.Unmarshal(data, &v); err != nil {
return err return err
} }