package core import ( "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/core/keys" "github.com/evcc-io/evcc/core/vehicle" ) // PublishEffectiveValues publishes all effective values func (lp *Loadpoint) PublishEffectiveValues() { lp.publish(keys.EffectivePriority, lp.EffectivePriority()) lp.publish(keys.EffectivePlanTime, lp.EffectivePlanTime()) lp.publish(keys.EffectivePlanSoc, lp.EffectivePlanSoc()) lp.publish(keys.EffectiveMinCurrent, lp.effectiveMinCurrent()) lp.publish(keys.EffectiveMaxCurrent, lp.effectiveMaxCurrent()) lp.publish(keys.EffectiveLimitSoc, lp.effectiveLimitSoc()) } // EffectivePriority returns the effective priority func (lp *Loadpoint) EffectivePriority() int { if v := lp.GetVehicle(); v != nil { if res, ok := v.OnIdentified().GetPriority(); ok { return res } } return lp.GetPriority() } // vehiclePlanSoc returns the next vehicle plan time and soc func (lp *Loadpoint) vehiclePlanSoc() (time.Time, int) { if v := lp.GetVehicle(); v != nil { return vehicle.Settings(lp.log, v).GetPlanSoc() } return time.Time{}, 0 } // EffectivePlanSoc returns the soc target for the current plan func (lp *Loadpoint) EffectivePlanSoc() int { _, soc := lp.vehiclePlanSoc() return soc } // EffectivePlanTime returns the effective plan time func (lp *Loadpoint) EffectivePlanTime() time.Time { if lp.socBasedPlanning() { ts, _ := lp.vehiclePlanSoc() return ts } ts, _ := lp.GetPlanEnergy() return ts } // SocBasedPlanning returns true if soc based planning is enabled func (lp *Loadpoint) SocBasedPlanning() bool { return lp.socBasedPlanning() } // effectiveMinCurrent returns the effective min current func (lp *Loadpoint) effectiveMinCurrent() float64 { lpMin := lp.GetMinCurrent() var vehicleMin, chargerMin float64 if v := lp.GetVehicle(); v != nil { if res, ok := v.OnIdentified().GetMinCurrent(); ok { vehicleMin = res } } if c, ok := lp.charger.(api.CurrentLimiter); ok { if res, _, err := c.GetMinMaxCurrent(); err == nil { chargerMin = res } } switch { case max(vehicleMin, chargerMin) == 0: return lpMin case chargerMin > 0: return max(vehicleMin, chargerMin) default: return max(vehicleMin, lpMin) } } // effectiveMaxCurrent returns the effective max current func (lp *Loadpoint) effectiveMaxCurrent() float64 { maxCurrent := lp.GetMaxCurrent() if v := lp.GetVehicle(); v != nil { if res, ok := v.OnIdentified().GetMaxCurrent(); ok && res > 0 { maxCurrent = min(maxCurrent, res) } } if c, ok := lp.charger.(api.CurrentLimiter); ok { if _, res, err := c.GetMinMaxCurrent(); err == nil && res > 0 { maxCurrent = min(maxCurrent, res) } } return maxCurrent } // effectiveLimitSoc returns the effective session limit soc // TODO take vehicle api limits into account func (lp *Loadpoint) effectiveLimitSoc() int { lp.RLock() defer lp.RUnlock() if lp.limitSoc > 0 { return lp.limitSoc } if v := lp.GetVehicle(); v != nil { if soc := vehicle.Settings(lp.log, v).GetLimitSoc(); soc > 0 { return soc } } // MUST return 100 here as UI looks at effectiveLimitSoc and not limitSoc (VehicleSoc.vue) return 100 } // effectiveStepPower returns the effective step power for the currently active phases func (lp *Loadpoint) effectiveStepPower() float64 { return Voltage * float64(lp.ActivePhases()) } // EffectiveMinPower returns the effective min power for the minimum active phases func (lp *Loadpoint) EffectiveMinPower() float64 { return Voltage * lp.effectiveMinCurrent() * float64(lp.minActivePhases()) } // EffectiveMaxPower returns the effective max power taking vehicle capabilities and phase scaling into account func (lp *Loadpoint) EffectiveMaxPower() float64 { return Voltage * lp.effectiveMaxCurrent() * float64(lp.maxActivePhases()) }