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
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue