parent
fbfe63fce5
commit
dbd4c4fd92
25 changed files with 185 additions and 114 deletions
|
|
@ -10,4 +10,5 @@ const (
|
|||
IntegratedDevice
|
||||
Heating
|
||||
Retryable
|
||||
WelcomeCharge
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
const _FeatureName = "OfflineCoarseCurrentIntegratedDeviceHeatingRetryable"
|
||||
const _FeatureName = "OfflineCoarseCurrentIntegratedDeviceHeatingRetryableWelcomeCharge"
|
||||
|
||||
var _FeatureIndex = [...]uint8{0, 7, 20, 36, 43, 52}
|
||||
var _FeatureIndex = [...]uint8{0, 7, 20, 36, 43, 52, 65}
|
||||
|
||||
const _FeatureLowerName = "offlinecoarsecurrentintegrateddeviceheatingretryable"
|
||||
const _FeatureLowerName = "offlinecoarsecurrentintegrateddeviceheatingretryablewelcomecharge"
|
||||
|
||||
func (i Feature) String() string {
|
||||
i -= 1
|
||||
|
|
@ -30,9 +30,10 @@ func _FeatureNoOp() {
|
|||
_ = x[IntegratedDevice-(3)]
|
||||
_ = x[Heating-(4)]
|
||||
_ = x[Retryable-(5)]
|
||||
_ = x[WelcomeCharge-(6)]
|
||||
}
|
||||
|
||||
var _FeatureValues = []Feature{Offline, CoarseCurrent, IntegratedDevice, Heating, Retryable}
|
||||
var _FeatureValues = []Feature{Offline, CoarseCurrent, IntegratedDevice, Heating, Retryable, WelcomeCharge}
|
||||
|
||||
var _FeatureNameToValueMap = map[string]Feature{
|
||||
_FeatureName[0:7]: Offline,
|
||||
|
|
@ -45,6 +46,8 @@ var _FeatureNameToValueMap = map[string]Feature{
|
|||
_FeatureLowerName[36:43]: Heating,
|
||||
_FeatureName[43:52]: Retryable,
|
||||
_FeatureLowerName[43:52]: Retryable,
|
||||
_FeatureName[52:65]: WelcomeCharge,
|
||||
_FeatureLowerName[52:65]: WelcomeCharge,
|
||||
}
|
||||
|
||||
var _FeatureNames = []string{
|
||||
|
|
@ -53,6 +56,7 @@ var _FeatureNames = []string{
|
|||
_FeatureName[20:36],
|
||||
_FeatureName[36:43],
|
||||
_FeatureName[43:52],
|
||||
_FeatureName[52:65],
|
||||
}
|
||||
|
||||
// FeatureString retrieves an enum value from the enum constants string name.
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ export default {
|
|||
|
||||
// details
|
||||
vehicleClimaterActive: Boolean,
|
||||
vehicleWelcomeActive: Boolean,
|
||||
chargePower: Number,
|
||||
chargedEnergy: Number,
|
||||
chargeRemainingDuration: Number,
|
||||
|
|
|
|||
17
assets/js/components/MaterialIcon/Welcome.vue
Normal file
17
assets/js/components/MaterialIcon/Welcome.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<svg :style="svgStyle" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.875 20q.1 0 .2-.05t.15-.1l8.2-8.2q.3-.3.438-.675t.137-.75q0-.4-.137-.763t-.438-.637l-4.25-4.25q-.275-.3-.638-.437T14.776 4q-.375 0-.75.138t-.675.437l-.275.275l1.85 1.875q.375.35.55.8t.175.95q0 1.05-.712 1.763t-1.763.712q-.5 0-.962-.175t-.813-.525L9.525 8.4L5.15 12.775q-.075.075-.112.163T5 13.125q0 .2.15.363t.35.162q.1 0 .2-.05t.15-.1l3.4-3.4l1.4 1.4l-3.375 3.4q-.075.075-.112.163t-.038.187q0 .2.15.35t.35.15q.1 0 .2-.05t.15-.1l3.4-3.375l1.4 1.4l-3.375 3.4q-.075.05-.112.15t-.038.2q0 .2.15.35t.35.15q.1 0 .188-.038t.162-.112l3.4-3.375l1.4 1.4l-3.4 3.4q-.075.075-.112.162t-.038.188q0 .2.163.35t.362.15m-.025 2q-.925 0-1.637-.612t-.838-1.538q-.85-.125-1.425-.7t-.7-1.425q-.85-.125-1.412-.712T5.15 15.6q-.95-.125-1.55-.825t-.6-1.65q0-.5.188-.962t.537-.813l5.8-5.775L12.8 8.85q.05.075.15.113t.2.037q.225 0 .375-.137t.15-.363q0-.1-.038-.2t-.112-.15L9.95 4.575q-.275-.3-.637-.437T8.55 4q-.375 0-.75.138t-.675.437L3.6 8.125q-.225.225-.375.525t-.2.6t0 .613t.2.587l-1.45 1.45q-.425-.575-.625-1.262T1 9.25t.35-1.362t.825-1.188L5.7 3.175Q6.3 2.6 7.038 2.3T8.55 2t1.513.3t1.312.875l.275.275l.275-.275q.6-.575 1.338-.875t1.512-.3t1.513.3t1.312.875L21.825 7.4q.575.575.875 1.325t.3 1.525t-.3 1.513t-.875 1.312l-8.2 8.175q-.35.35-.812.55t-.963.2M9.375 8"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icon from "../../mixins/icon";
|
||||
|
||||
export default {
|
||||
name: "Welcome",
|
||||
mixins: [icon],
|
||||
};
|
||||
</script>
|
||||
|
|
@ -95,6 +95,7 @@ export default {
|
|||
chargedEnergy: Number,
|
||||
charging: Boolean,
|
||||
vehicleClimaterActive: Boolean,
|
||||
vehicleWelcomeActive: Boolean,
|
||||
connected: Boolean,
|
||||
currency: String,
|
||||
effectiveLimitSoc: Number,
|
||||
|
|
|
|||
|
|
@ -232,5 +232,8 @@ const planProjectedEnd = getFutureTime(5, 43);
|
|||
vehicleClimaterActive
|
||||
/>
|
||||
</Variant>
|
||||
<Variant title="welcome charge">
|
||||
<VehicleStatus connected charging vehicleWelcomeActive />
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,15 @@
|
|||
>
|
||||
<ClimaterIcon />
|
||||
</div>
|
||||
<div
|
||||
v-if="vehicleWelcomeActive"
|
||||
ref="vehicleWelcome"
|
||||
data-bs-toggle="tooltip"
|
||||
class="entry"
|
||||
data-testid="vehicle-status-welcome"
|
||||
>
|
||||
<WelcomeIcon />
|
||||
</div>
|
||||
|
||||
<!-- smart cost -->
|
||||
<button
|
||||
|
|
@ -140,6 +149,7 @@ import VehicleMinSocIcon from "./MaterialIcon/VehicleMinSoc.vue";
|
|||
import SunDownIcon from "./MaterialIcon/SunDown.vue";
|
||||
import SunUpIcon from "./MaterialIcon/SunUp.vue";
|
||||
import Tooltip from "bootstrap/js/dist/tooltip";
|
||||
import WelcomeIcon from "./MaterialIcon/Welcome.vue";
|
||||
|
||||
export default {
|
||||
name: "VehicleStatus",
|
||||
|
|
@ -152,6 +162,7 @@ export default {
|
|||
VehicleMinSocIcon,
|
||||
SunDownIcon,
|
||||
SunUpIcon,
|
||||
WelcomeIcon,
|
||||
},
|
||||
mixins: [formatter],
|
||||
props: {
|
||||
|
|
@ -183,6 +194,7 @@ export default {
|
|||
tariffCo2: Number,
|
||||
tariffGrid: Number,
|
||||
vehicleClimaterActive: Boolean,
|
||||
vehicleWelcomeActive: Boolean,
|
||||
vehicleLimitSoc: Number,
|
||||
},
|
||||
emits: ["open-loadpoint-settings", "open-minsoc-settings", "open-plan-modal"],
|
||||
|
|
@ -194,6 +206,7 @@ export default {
|
|||
planActiveTooltip: null,
|
||||
minSocTooltip: null,
|
||||
vehicleClimaterTooltip: null,
|
||||
vehicleWelcomeTooltip: null,
|
||||
smartCostTooltip: null,
|
||||
vehicleLimitTooltip: null,
|
||||
};
|
||||
|
|
@ -205,6 +218,7 @@ export default {
|
|||
this.updatePhaseTooltip();
|
||||
this.updatePvTooltip();
|
||||
this.updateVehicleClimaterTooltip();
|
||||
this.updateVehicleWelcomeTooltip();
|
||||
this.updateSmartCostTooltip();
|
||||
this.updateVehicleLimitTooltip();
|
||||
},
|
||||
|
|
@ -227,6 +241,9 @@ export default {
|
|||
vehicleClimaterTooltipContent() {
|
||||
this.$nextTick(this.updateVehicleClimaterTooltip);
|
||||
},
|
||||
vehicleWelcomeTooltipContent() {
|
||||
this.$nextTick(this.updateVehicleWelcomeTooltip);
|
||||
},
|
||||
smartCostTooltipContent() {
|
||||
this.$nextTick(this.updateSmartCostTooltip);
|
||||
},
|
||||
|
|
@ -399,8 +416,17 @@ export default {
|
|||
return "";
|
||||
},
|
||||
vehicleClimaterTooltipContent() {
|
||||
if (!this.vehicleClimaterActive) {
|
||||
return "";
|
||||
}
|
||||
return this.$t("main.vehicleStatus.climating");
|
||||
},
|
||||
vehicleWelcomeTooltipContent() {
|
||||
if (!this.vehicleWelcomeActive) {
|
||||
return "";
|
||||
}
|
||||
return this.$t("main.vehicleStatus.welcome");
|
||||
},
|
||||
chargerStatus() {
|
||||
const t = (key, data) => {
|
||||
if (this.heating) {
|
||||
|
|
@ -428,91 +454,6 @@ export default {
|
|||
return t("charging");
|
||||
}
|
||||
|
||||
return t("connected");
|
||||
},
|
||||
message: function () {
|
||||
const t = (key, data) => {
|
||||
if (this.heating) {
|
||||
// check for special heating status translation
|
||||
const name = `main.heatingStatus.${key}`;
|
||||
if (this.$te(name, DEFAULT_LOCALE)) {
|
||||
return this.$t(name, data);
|
||||
}
|
||||
}
|
||||
return this.$t(`main.vehicleStatus.${key}`, data);
|
||||
};
|
||||
|
||||
if (!this.connected) {
|
||||
return t("disconnected");
|
||||
}
|
||||
// min charge active
|
||||
if (this.minSoc > 0 && this.vehicleSoc < this.minSoc) {
|
||||
return t("minCharge", { soc: this.fmtPercentage(this.minSoc) });
|
||||
}
|
||||
|
||||
// plan
|
||||
if (!this.chargingPlanDisabled && this.effectivePlanTime) {
|
||||
if (this.planActive && this.charging) {
|
||||
return t("targetChargeActive");
|
||||
}
|
||||
if (this.planActive && this.enabled) {
|
||||
return t("targetChargeWaitForVehicle");
|
||||
}
|
||||
if (this.planProjectedStart) {
|
||||
return t("targetChargePlanned", {
|
||||
time: this.fmtAbsoluteDate(new Date(this.planProjectedStart)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// clean or cheap energy
|
||||
if (this.charging && this.smartCostActive) {
|
||||
return this.smartCostType === CO2_TYPE
|
||||
? t("cleanEnergyCharging", {
|
||||
co2: this.fmtCo2Short(this.tariffCo2),
|
||||
limit: this.fmtCo2Short(this.smartCostLimit),
|
||||
})
|
||||
: t("cheapEnergyCharging", {
|
||||
price: this.fmtPricePerKWh(this.tariffGrid, this.currency, true),
|
||||
limit: this.fmtPricePerKWh(this.smartCostLimit, this.currency, true),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.pvTimerActive && !this.enabled && this.pvAction === "enable") {
|
||||
return t("pvEnable", {
|
||||
remaining: this.fmtDuration(this.pvRemainingInterpolated),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.enabled && this.vehicleClimaterActive) {
|
||||
return t("climating");
|
||||
}
|
||||
|
||||
if (this.enabled && !this.charging) {
|
||||
if (this.vehicleLimitSoc > 0 && this.vehicleSoc >= this.vehicleLimitSoc - 1) {
|
||||
return t("vehicleLimitReached", {
|
||||
soc: this.fmtPercentage(this.vehicleLimitSoc),
|
||||
});
|
||||
}
|
||||
return t("waitForVehicle");
|
||||
}
|
||||
|
||||
if (this.pvTimerActive && this.charging && this.pvAction === "disable") {
|
||||
return t("pvDisable", {
|
||||
remaining: this.fmtDuration(this.pvRemainingInterpolated),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.phaseTimerActive) {
|
||||
return t(this.phaseAction, {
|
||||
remaining: this.fmtDuration(this.phaseRemainingInterpolated),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.charging) {
|
||||
return t("charging");
|
||||
}
|
||||
|
||||
return t("connected");
|
||||
},
|
||||
},
|
||||
|
|
@ -587,6 +528,13 @@ export default {
|
|||
this.$refs.vehicleClimater
|
||||
);
|
||||
},
|
||||
updateVehicleWelcomeTooltip() {
|
||||
this.vehicleWelcomeTooltip = this.updateTooltip(
|
||||
this.vehicleWelcomeTooltip,
|
||||
this.vehicleWelcomeTooltipContent,
|
||||
this.$refs.vehicleWelcome
|
||||
);
|
||||
},
|
||||
updateSmartCostTooltip() {
|
||||
this.smartCostTooltip = this.updateTooltip(
|
||||
this.smartCostTooltip,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import (
|
|||
|
||||
// Keba is an api.Charger implementation
|
||||
type Keba struct {
|
||||
*embed
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
|
@ -68,15 +69,20 @@ func init() {
|
|||
|
||||
// NewKebaFromConfig creates a new Keba ModbusTCP charger
|
||||
func NewKebaFromConfig(other map[string]interface{}) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
ID: 255,
|
||||
cc := struct {
|
||||
embed `mapstructure:",squash"`
|
||||
modbus.TcpSettings
|
||||
}{
|
||||
TcpSettings: modbus.TcpSettings{
|
||||
ID: 255,
|
||||
},
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wb, err := NewKeba(cc.URI, cc.ID)
|
||||
wb, err := NewKeba(cc.embed, cc.URI, cc.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -129,7 +135,7 @@ func NewKebaFromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
}
|
||||
|
||||
// NewKeba creates a new charger
|
||||
func NewKeba(uri string, slaveID uint8) (*Keba, error) {
|
||||
func NewKeba(embed embed, uri string, slaveID uint8) (*Keba, error) {
|
||||
conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, slaveID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -143,8 +149,9 @@ func NewKeba(uri string, slaveID uint8) (*Keba, error) {
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Keba{
|
||||
log: log,
|
||||
conn: conn,
|
||||
embed: &embed,
|
||||
log: log,
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
return wb, err
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ func NewAdapter(lp loadpoint.API, c *Coordinator) API {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *adapter) GetVehicles() []api.Vehicle {
|
||||
return a.c.GetVehicles()
|
||||
func (a *adapter) GetVehicles(availableOnly bool) []api.Vehicle {
|
||||
return a.c.GetVehicles(availableOnly)
|
||||
}
|
||||
|
||||
func (a *adapter) Owner(v api.Vehicle) loadpoint.API {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
// API is the coordinator API
|
||||
type API interface {
|
||||
// GetVehicles returns the list of all vehicles
|
||||
GetVehicles() []api.Vehicle
|
||||
// GetVehicles returns the list of all vehicles, filtered by availability
|
||||
GetVehicles(availableOnly bool) []api.Vehicle
|
||||
|
||||
// Owner returns the loadpoint that currently owns the vehicle
|
||||
Owner(api.Vehicle) loadpoint.API
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package coordinator
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
|
|
@ -27,11 +26,18 @@ func New(log *util.Logger, vehicles []api.Vehicle) *Coordinator {
|
|||
}
|
||||
|
||||
// GetVehicles returns the list of all vehicles
|
||||
func (c *Coordinator) GetVehicles() []api.Vehicle {
|
||||
func (c *Coordinator) GetVehicles(availableOnly bool) []api.Vehicle {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
return slices.Clone(c.vehicles)
|
||||
res := make([]api.Vehicle, 0, len(c.vehicles))
|
||||
for _, v := range c.vehicles {
|
||||
if _, tracked := c.tracked[v]; !availableOnly || availableOnly && !tracked {
|
||||
res = append(res, v)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Owner returns the loadpoint that currently owns the vehicle
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ func NewDummy() API {
|
|||
return new(dummy)
|
||||
}
|
||||
|
||||
func (a *dummy) GetVehicles() []api.Vehicle {
|
||||
func (a *dummy) GetVehicles(_ bool) []api.Vehicle {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const (
|
|||
PlanSoc = "planSoc" // charge plan soc goal
|
||||
PlanActive = "planActive" // charge plan has determined current slot to be an active slot
|
||||
PlanProjectedStart = "planProjectedStart" // charge plan start time (earliest slot)
|
||||
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
|
||||
|
||||
// remote control
|
||||
|
|
@ -76,4 +76,5 @@ const (
|
|||
VehicleSoc = "vehicleSoc" // vehicle soc
|
||||
VehicleLimitSoc = "vehicleLimitSoc" // vehicle api soc limit
|
||||
VehicleClimaterActive = "vehicleClimaterActive" // vehicle climater active
|
||||
VehicleWelcomeActive = "vehicleWelcomeActive" // vehicle might need welcome charge
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -885,7 +886,7 @@ func (lp *Loadpoint) charging() bool {
|
|||
return lp.GetStatus() == api.StatusC
|
||||
}
|
||||
|
||||
// charging returns the EVs charging state
|
||||
// setStatus updates the internal charging state according to EV
|
||||
func (lp *Loadpoint) setStatus(status api.ChargeStatus) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
|
@ -993,10 +994,12 @@ func statusEvents(prevStatus, status api.ChargeStatus) []string {
|
|||
}
|
||||
|
||||
// updateChargerStatus updates charger status and detects car connected/disconnected events
|
||||
func (lp *Loadpoint) updateChargerStatus() error {
|
||||
func (lp *Loadpoint) updateChargerStatus() (bool, error) {
|
||||
var welcomeCharge bool
|
||||
|
||||
status, err := lp.charger.Status()
|
||||
if err != nil {
|
||||
return fmt.Errorf("charger status: %w", err)
|
||||
return false, fmt.Errorf("charger status: %w", err)
|
||||
}
|
||||
|
||||
lp.log.DEBUG.Printf("charger status: %s", status)
|
||||
|
|
@ -1011,6 +1014,20 @@ func (lp *Loadpoint) updateChargerStatus() error {
|
|||
if prevStatus != api.StatusNone {
|
||||
switch ev {
|
||||
case evVehicleConnect:
|
||||
welcomeCharge = lp.chargerHasFeature(api.WelcomeCharge)
|
||||
|
||||
// Enable charging on connect if any available vehicle requires it.
|
||||
// We're using the PV timer to disable after the welcome
|
||||
if !welcomeCharge {
|
||||
for _, v := range lp.availableVehicles() {
|
||||
if slices.Contains(v.Features(), api.WelcomeCharge) {
|
||||
welcomeCharge = true
|
||||
lp.log.DEBUG.Printf("welcome charge: %s", v.Title())
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lp.pushEvent(evVehicleConnect)
|
||||
case evVehicleDisconnect:
|
||||
lp.pushEvent(evVehicleDisconnect)
|
||||
|
|
@ -1022,7 +1039,7 @@ func (lp *Loadpoint) updateChargerStatus() error {
|
|||
lp.bus.Publish(evChargeCurrent, lp.chargeCurrent)
|
||||
}
|
||||
|
||||
return nil
|
||||
return welcomeCharge, nil
|
||||
}
|
||||
|
||||
// effectiveCurrent returns the currently effective charging current
|
||||
|
|
@ -1635,11 +1652,13 @@ func (lp *Loadpoint) Update(sitePower float64, smartCostActive bool, smartCostNe
|
|||
lp.PublishEffectiveValues()
|
||||
|
||||
// read and publish status
|
||||
if err := lp.updateChargerStatus(); err != nil {
|
||||
welcomeCharge, err := lp.updateChargerStatus()
|
||||
if err != nil {
|
||||
lp.log.ERROR.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
lp.publish(keys.VehicleWelcomeActive, welcomeCharge)
|
||||
lp.publish(keys.Connected, lp.connected())
|
||||
lp.publish(keys.Charging, lp.charging())
|
||||
|
||||
|
|
@ -1664,9 +1683,6 @@ func (lp *Loadpoint) Update(sitePower float64, smartCostActive bool, smartCostNe
|
|||
return
|
||||
}
|
||||
|
||||
// check if car connected and ready for charging
|
||||
var err error
|
||||
|
||||
// track if remote disabled is actually active
|
||||
remoteDisabled := loadpoint.RemoteEnable
|
||||
|
||||
|
|
@ -1691,7 +1707,11 @@ func (lp *Loadpoint) Update(sitePower float64, smartCostActive bool, smartCostNe
|
|||
fallthrough
|
||||
|
||||
case mode == api.ModeOff:
|
||||
err = lp.setLimit(0)
|
||||
var current float64
|
||||
if welcomeCharge {
|
||||
current = lp.effectiveMinCurrent()
|
||||
}
|
||||
err = lp.setLimit(current)
|
||||
|
||||
// minimum or target charging
|
||||
case lp.minSocNotReached() || plannerActive:
|
||||
|
|
@ -1726,6 +1746,11 @@ func (lp *Loadpoint) Update(sitePower float64, smartCostActive bool, smartCostNe
|
|||
targetCurrent = lp.effectiveMinCurrent()
|
||||
}
|
||||
|
||||
if targetCurrent == 0 && welcomeCharge {
|
||||
targetCurrent = lp.effectiveMinCurrent()
|
||||
lp.resetPVTimer()
|
||||
}
|
||||
|
||||
// Sunny Home Manager
|
||||
if lp.remoteControlled(loadpoint.RemoteSoftDisable) {
|
||||
remoteDisabled = loadpoint.RemoteSoftDisable
|
||||
|
|
|
|||
|
|
@ -20,12 +20,20 @@ const (
|
|||
vehicleDetectDuration = 10 * time.Minute
|
||||
)
|
||||
|
||||
// availableVehicles is the slice of vehicles from the coordinator that are available
|
||||
func (lp *Loadpoint) availableVehicles() []api.Vehicle {
|
||||
if lp.coordinator == nil {
|
||||
return nil
|
||||
}
|
||||
return lp.coordinator.GetVehicles(true)
|
||||
}
|
||||
|
||||
// coordinatedVehicles is the slice of vehicles from the coordinator
|
||||
func (lp *Loadpoint) coordinatedVehicles() []api.Vehicle {
|
||||
if lp.coordinator == nil {
|
||||
return nil
|
||||
}
|
||||
return lp.coordinator.GetVehicles()
|
||||
return lp.coordinator.GetVehicles(false)
|
||||
}
|
||||
|
||||
// setVehicleIdentifier updated the vehicle id as read from the charger
|
||||
|
|
|
|||
|
|
@ -541,6 +541,7 @@ unknown = ""
|
|||
vehicleLimit = "Fahrzeuglimit."
|
||||
vehicleLimitReached = "Fahrzeuglimit erreicht."
|
||||
waitForVehicle = "Ladebereit. Warte auf Fahrzeug …"
|
||||
welcome = "Kurze initiale Ladung zur Bestätigung der Verbindung."
|
||||
|
||||
[notifications]
|
||||
dismissAll = "Meldungen entfernen"
|
||||
|
|
|
|||
|
|
@ -539,6 +539,7 @@ unknown = ""
|
|||
vehicleLimit = "Vehicle limit."
|
||||
vehicleLimitReached = "Vehicle limit reached."
|
||||
waitForVehicle = "Ready. Waiting for vehicle…"
|
||||
welcome = "Short initial charge to confirm connection."
|
||||
|
||||
[notifications]
|
||||
dismissAll = "Dismiss all"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ params:
|
|||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
id: 255
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: keba-modbus
|
||||
{{- include "modbus" . }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ params:
|
|||
# - EU
|
||||
default: EU
|
||||
advanced: true
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: bmw
|
||||
{{ include "vehicle-base" . }}
|
||||
|
|
@ -22,3 +24,6 @@ render: |
|
|||
{{- if ne .region "EU" }}
|
||||
region: {{ .region }}
|
||||
{{- end }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@ products:
|
|||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-identify
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: dacia
|
||||
{{ include "vehicle-base" . }}
|
||||
{{ include "vehicle-identify" . }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ params:
|
|||
- name: pin
|
||||
mask: true
|
||||
- preset: vehicle-identify
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: fiat
|
||||
{{ include "vehicle-base" . }}
|
||||
|
|
@ -16,3 +18,6 @@ render: |
|
|||
pin: {{ .pin }} # mandatory to deep refresh Soc
|
||||
{{- end }}
|
||||
{{ include "vehicle-identify" . }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ params:
|
|||
# - EU
|
||||
default: EU
|
||||
advanced: true
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: mini
|
||||
{{ include "vehicle-base" . }}
|
||||
|
|
@ -22,3 +24,6 @@ render: |
|
|||
{{- if ne .region "EU" }}
|
||||
region: {{ .region }}
|
||||
{{- end }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ products:
|
|||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-identify
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: cupra
|
||||
{{ include "vehicle-base" . }}
|
||||
{{ include "vehicle-identify" . }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ products:
|
|||
params:
|
||||
- preset: vehicle-base
|
||||
- preset: vehicle-identify
|
||||
- name: welcomecharge
|
||||
advanced: true
|
||||
render: |
|
||||
type: smart-hello
|
||||
{{ include "vehicle-base" . }}
|
||||
{{ include "vehicle-identify" . }}
|
||||
{{- if .welcomecharge }}
|
||||
features: ["welcomecharge"]
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -289,6 +289,18 @@ params:
|
|||
help:
|
||||
en: The AIN is printed on the type label on the back of the device. Embed it in double quotes in case of leading zeroes.
|
||||
de: Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. Bei führenden Nullen bitte in doppelte Hochkommata setzen.
|
||||
- name: welcomecharge
|
||||
type: bool
|
||||
description:
|
||||
en: Charge on connection
|
||||
de: Laden bei Verbindung
|
||||
help:
|
||||
en: |
|
||||
Charger will enable charging for short time when vehicle is connected, irrespective of configured charge mode.
|
||||
This is useful for vehicles that require power supply when connecting.
|
||||
de: |
|
||||
Wallbox gibt kurzzeitige Ladefreigabe bei Fahrzeugverbindung. Das ermöglicht es Fahrzeugen, die eine Stromversorgung beim Anschließen benötigen,
|
||||
einen Fehlerzustand zu vermeiden.
|
||||
|
||||
presets:
|
||||
vehicle-base:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue