Ocpp: add disconnect required status (#15659)

This commit is contained in:
andig 2024-08-25 12:10:17 +02:00 • committed by GitHub
parent f8b7f77a9f
commit d03705e1a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 107 additions and 33 deletions

View file

@ -6,4 +6,5 @@ type Reason int
const ( const (
ReasonUnknown Reason = iota ReasonUnknown Reason = iota
ReasonWaitingForAuthorization ReasonWaitingForAuthorization
ReasonDisconnectRequired
) )

View file

@ -7,11 +7,11 @@ import (
"strings" "strings"
) )
const _ReasonName = "unknownwaitingforauthorization" const _ReasonName = "unknownwaitingforauthorizationdisconnectrequired"
var _ReasonIndex = [...]uint8{0, 7, 30} var _ReasonIndex = [...]uint8{0, 7, 30, 48}
const _ReasonLowerName = "unknownwaitingforauthorization" const _ReasonLowerName = "unknownwaitingforauthorizationdisconnectrequired"
func (i Reason) String() string { func (i Reason) String() string {
if i < 0 || i >= Reason(len(_ReasonIndex)-1) { if i < 0 || i >= Reason(len(_ReasonIndex)-1) {
@ -26,20 +26,24 @@ func _ReasonNoOp() {
var x [1]struct{} var x [1]struct{}
_ = x[ReasonUnknown-(0)] _ = x[ReasonUnknown-(0)]
_ = x[ReasonWaitingForAuthorization-(1)] _ = x[ReasonWaitingForAuthorization-(1)]
_ = x[ReasonDisconnectRequired-(2)]
} }
var _ReasonValues = []Reason{ReasonUnknown, ReasonWaitingForAuthorization} var _ReasonValues = []Reason{ReasonUnknown, ReasonWaitingForAuthorization, ReasonDisconnectRequired}
var _ReasonNameToValueMap = map[string]Reason{ var _ReasonNameToValueMap = map[string]Reason{
_ReasonName[0:7]: ReasonUnknown, _ReasonName[0:7]: ReasonUnknown,
_ReasonLowerName[0:7]: ReasonUnknown, _ReasonLowerName[0:7]: ReasonUnknown,
_ReasonName[7:30]: ReasonWaitingForAuthorization, _ReasonName[7:30]: ReasonWaitingForAuthorization,
_ReasonLowerName[7:30]: ReasonWaitingForAuthorization, _ReasonLowerName[7:30]: ReasonWaitingForAuthorization,
_ReasonName[30:48]: ReasonDisconnectRequired,
_ReasonLowerName[30:48]: ReasonDisconnectRequired,
} }
var _ReasonNames = []string{ var _ReasonNames = []string{
_ReasonName[0:7], _ReasonName[0:7],
_ReasonName[7:30], _ReasonName[7:30],
_ReasonName[30:48],
} }
// ReasonString retrieves an enum value from the enum constants string name. // ReasonString retrieves an enum value from the enum constants string name.

View file

@ -141,7 +141,7 @@ export default {
sessionSolarPercentage: Number, sessionSolarPercentage: Number,
// charger // charger
chargerAwaitingAuthorization: Boolean, chargerStatusReason: String,
chargerFeatureIntegratedDevice: Boolean, chargerFeatureIntegratedDevice: Boolean,
chargerFeatureHeating: Boolean, chargerFeatureHeating: Boolean,
chargerIcon: String, chargerIcon: String,

View file

@ -0,0 +1,21 @@
<template>
<svg :style="svgStyle" viewBox="0 0 32 32">
<path
fill="currentColor"
d="M5.505,24.609c-0.595,-0.935 -0.94,-2.041 -0.94,-3.222c-0,-1.632 0.661,-3.198 1.831,-4.336l1.995,-1.994c0.52,-0.521 1.364,-0.521 1.885,0l0.391,0.391l1.724,-1.724c0.52,-0.52 1.365,-0.52 1.885,-0c0.52,0.52 0.52,1.365 0,1.885l-1.724,1.724l2.115,2.115l1.724,-1.724c0.52,-0.52 1.365,-0.52 1.885,-0c0.52,0.52 0.52,1.365 0,1.885l-1.724,1.724l0.391,0.391c0.521,0.521 0.521,1.365 -0,1.885c-0,0 -1.994,1.995 -1.994,1.995c-1.138,1.17 -2.704,1.831 -4.336,1.831c-1.181,0 -2.287,-0.345 -3.222,-0.94l-2.448,2.448c-0.521,0.52 -1.365,0.52 -1.886,-0c-0.52,-0.521 -0.52,-1.365 0,-1.886l2.448,-2.448Zm4.219,-6.333l-0.391,-0.39l-1.057,1.057c-0.005,0.005 -0.01,0.01 -0.015,0.015c-0.658,0.637 -1.03,1.514 -1.03,2.429c0,0.797 0.282,1.533 0.75,2.114c0.106,0.059 0.205,0.133 0.295,0.223c0.09,0.09 0.164,0.189 0.223,0.295c0.581,0.468 1.317,0.75 2.114,0.75c0.915,-0 1.792,-0.372 2.429,-1.03c0.005,-0.005 0.01,-0.01 0.015,-0.015c0,-0 1.057,-1.057 1.057,-1.057l-4.39,-4.391Zm14.885,-12.771l2.448,-2.448c0.521,-0.52 1.365,-0.52 1.886,0c0.52,0.521 0.52,1.365 -0,1.886l-2.448,2.448c0.595,0.935 0.94,2.041 0.94,3.222c0,1.632 -0.661,3.198 -1.831,4.336l-1.995,1.994c-0.52,0.521 -1.364,0.521 -1.885,-0l-6.667,-6.667c-0.521,-0.521 -0.521,-1.365 0,-1.885c0,-0 1.994,-1.995 1.994,-1.995c1.138,-1.17 2.704,-1.831 4.336,-1.831c1.181,-0 2.287,0.345 3.222,0.94Zm-0.59,2.994c-0.106,-0.059 -0.205,-0.133 -0.295,-0.223c-0.09,-0.09 -0.164,-0.189 -0.223,-0.295c-0.581,-0.468 -1.317,-0.75 -2.114,-0.75c-0.915,0 -1.792,0.372 -2.429,1.03c-0.005,0.005 -0.01,0.01 -0.015,0.015c-0,0 -1.057,1.057 -1.057,1.057l4.781,4.781l1.057,-1.057c0.005,-0.005 0.01,-0.01 0.015,-0.015c0.658,-0.637 1.03,-1.514 1.03,-2.429c-0,-0.797 -0.282,-1.533 -0.75,-2.114Z"
/>
<path
fill="currentColor"
d="M25.333,20l0.781,-0l-0.39,-0.391c-0.52,-0.52 -0.52,-1.365 -0,-1.885c0.52,-0.52 1.365,-0.52 1.885,-0l2.667,2.667c0.387,0.386 0.492,0.962 0.289,1.453c-0.066,0.161 -0.164,0.308 -0.289,0.432l-2.667,2.667c-0.52,0.52 -1.365,0.52 -1.885,-0c-0.52,-0.521 -0.52,-1.365 -0,-1.886l0.39,-0.39l-0.781,-0c-1.463,-0 -2.666,1.203 -2.666,2.666c-0,1.463 1.203,2.667 2.666,2.667c0.656,-0 1.289,-0.242 1.778,-0.679c0.549,-0.491 1.392,-0.444 1.883,0.105c0.49,0.548 0.443,1.392 -0.105,1.882c-0.978,0.875 -2.244,1.359 -3.556,1.359c-2.926,-0 -5.333,-2.408 -5.333,-5.334c-0,-2.925 2.408,-5.333 5.333,-5.333Z"
/>
</svg>
</template>
<script>
import icon from "../../mixins/icon";
export default {
name: "Reconnect",
mixins: [icon],
};
</script>

View file

@ -107,7 +107,7 @@ export default {
integratedDevice: Boolean, integratedDevice: Boolean,
limitEnergy: Number, limitEnergy: Number,
mode: String, mode: String,
chargerAwaitingAuthorization: Boolean, chargerStatusReason: String,
phaseAction: String, phaseAction: String,
phaseRemainingInterpolated: Number, phaseRemainingInterpolated: Number,
planActive: Boolean, planActive: Boolean,

View file

@ -84,6 +84,15 @@
> >
<RfidWaitIcon /> <RfidWaitIcon />
</div> </div>
<div
v-if="disconnectRequiredVisible"
ref="disconnectRequired"
class="entry text-warning"
data-bs-toggle="tooltip"
data-testid="vehicle-status-disconnect-required"
>
<ReconnectIcon />
</div>
<!-- smart cost --> <!-- smart cost -->
<button <button
@ -148,31 +157,36 @@ import DynamicPriceIcon from "./MaterialIcon/DynamicPrice.vue";
import { DEFAULT_LOCALE } from "../i18n"; import { DEFAULT_LOCALE } from "../i18n";
import formatter from "../mixins/formatter"; import formatter from "../mixins/formatter";
import { CO2_TYPE } from "../units"; import { CO2_TYPE } from "../units";
import PlanStartIcon from "./MaterialIcon/PlanStart.vue";
import PlanEndIcon from "./MaterialIcon/PlanEnd.vue";
import RfidWaitIcon from "./MaterialIcon/RfidWait.vue";
import ClimaterIcon from "./MaterialIcon/Climater.vue"; import ClimaterIcon from "./MaterialIcon/Climater.vue";
import VehicleLimitReachedIcon from "./MaterialIcon/VehicleLimitReached.vue"; import PlanEndIcon from "./MaterialIcon/PlanEnd.vue";
import VehicleLimitWarningIcon from "./MaterialIcon/VehicleLimitWarning.vue"; import PlanStartIcon from "./MaterialIcon/PlanStart.vue";
import VehicleLimitIcon from "./MaterialIcon/VehicleLimit.vue"; import ReconnectIcon from "./MaterialIcon/Reconnect.vue";
import VehicleMinSocIcon from "./MaterialIcon/VehicleMinSoc.vue"; import RfidWaitIcon from "./MaterialIcon/RfidWait.vue";
import SunDownIcon from "./MaterialIcon/SunDown.vue"; import SunDownIcon from "./MaterialIcon/SunDown.vue";
import SunUpIcon from "./MaterialIcon/SunUp.vue"; import SunUpIcon from "./MaterialIcon/SunUp.vue";
import Tooltip from "bootstrap/js/dist/tooltip"; import Tooltip from "bootstrap/js/dist/tooltip";
import VehicleLimitIcon from "./MaterialIcon/VehicleLimit.vue";
import VehicleLimitReachedIcon from "./MaterialIcon/VehicleLimitReached.vue";
import VehicleLimitWarningIcon from "./MaterialIcon/VehicleLimitWarning.vue";
import VehicleMinSocIcon from "./MaterialIcon/VehicleMinSoc.vue";
import WelcomeIcon from "./MaterialIcon/Welcome.vue"; import WelcomeIcon from "./MaterialIcon/Welcome.vue";
const REASON_AUTH = "waitingforauthorization";
const REASON_DISCONNECT = "disconnectrequired";
export default { export default {
name: "VehicleStatus", name: "VehicleStatus",
components: { components: {
DynamicPriceIcon,
PlanStartIcon,
PlanEndIcon,
RfidWaitIcon,
ClimaterIcon, ClimaterIcon,
VehicleLimitIcon, DynamicPriceIcon,
VehicleMinSocIcon, PlanEndIcon,
PlanStartIcon,
ReconnectIcon,
RfidWaitIcon,
SunDownIcon, SunDownIcon,
SunUpIcon, SunUpIcon,
VehicleLimitIcon,
VehicleMinSocIcon,
WelcomeIcon, WelcomeIcon,
}, },
mixins: [formatter], mixins: [formatter],
@ -180,7 +194,7 @@ export default {
vehicleSoc: Number, vehicleSoc: Number,
charging: Boolean, charging: Boolean,
chargingPlanDisabled: Boolean, chargingPlanDisabled: Boolean,
chargerAwaitingAuthorization: Boolean, chargerStatusReason: String,
connected: Boolean, connected: Boolean,
currency: String, currency: String,
effectiveLimitSoc: Number, effectiveLimitSoc: Number,
@ -222,6 +236,7 @@ export default {
smartCostTooltip: null, smartCostTooltip: null,
vehicleLimitTooltip: null, vehicleLimitTooltip: null,
awaitingAuthorizationTooltip: null, awaitingAuthorizationTooltip: null,
disconnectRequiredTooltip: null,
}; };
}, },
mounted() { mounted() {
@ -235,6 +250,7 @@ export default {
this.updateSmartCostTooltip(); this.updateSmartCostTooltip();
this.updateVehicleLimitTooltip(); this.updateVehicleLimitTooltip();
this.updateAwaitingAuthorizationTooltip(); this.updateAwaitingAuthorizationTooltip();
this.updateDisconnectRequiredTooltip();
}, },
watch: { watch: {
planActiveTooltipContent() { planActiveTooltipContent() {
@ -267,6 +283,9 @@ export default {
awaitingAuthorizationTooltipContent() { awaitingAuthorizationTooltipContent() {
this.$nextTick(this.updateAwaitingAuthorizationTooltip); this.$nextTick(this.updateAwaitingAuthorizationTooltip);
}, },
disconnectRequiredTooltipContent() {
this.$nextTick(this.updateDisconnectRequiredTooltip);
},
}, },
computed: { computed: {
phaseTimerActive() { phaseTimerActive() {
@ -307,7 +326,7 @@ export default {
return this.connected && this.vehicleLimitSoc > 0 && this.vehicleLimitSoc < limit; return this.connected && this.vehicleLimitSoc > 0 && this.vehicleLimitSoc < limit;
}, },
awaitingAuthorizationVisible() { awaitingAuthorizationVisible() {
return this.chargerAwaitingAuthorization; return this.chargerStatusReason === REASON_AUTH;
}, },
awaitingAuthorizationTooltipContent() { awaitingAuthorizationTooltipContent() {
if (!this.awaitingAuthorizationVisible) { if (!this.awaitingAuthorizationVisible) {
@ -315,6 +334,15 @@ export default {
} }
return this.$t("main.vehicleStatus.awaitingAuthorization"); return this.$t("main.vehicleStatus.awaitingAuthorization");
}, },
disconnectRequiredVisible() {
return this.chargerStatusReason === REASON_DISCONNECT;
},
disconnectRequiredTooltipContent() {
if (!this.disconnectRequiredVisible) {
return "";
}
return this.$t("main.vehicleStatus.disconnectRequired");
},
vehicleLimitTooltipContent() { vehicleLimitTooltipContent() {
if (!this.vehicleLimitVisible) { if (!this.vehicleLimitVisible) {
return ""; return "";
@ -584,6 +612,13 @@ export default {
this.$refs.awaitingAuthorization this.$refs.awaitingAuthorization
); );
}, },
updateDisconnectRequiredTooltip() {
this.updateTooltip(
this.disconnectRequiredTooltip,
this.disconnectRequiredTooltipContent,
this.$refs.disconnectRequired
);
},
updateTooltip: function (instance, content, ref, hoverOnly = false) { updateTooltip: function (instance, content, ref, hoverOnly = false) {
if (!content || !ref) { if (!content || !ref) {
if (instance) { if (instance) {

View file

@ -342,9 +342,20 @@ var _ api.StatusReasoner = (*OCPP)(nil)
func (c *OCPP) StatusReason() (api.Reason, error) { func (c *OCPP) StatusReason() (api.Reason, error) {
var res api.Reason var res api.Reason
if c.conn.NeedsAuthentication() {
res = api.ReasonWaitingForAuthorization s, err := c.conn.Status()
if err != nil {
return res, err
} }
switch {
case c.conn.NeedsAuthentication():
res = api.ReasonWaitingForAuthorization
case s == core.ChargePointStatusFinishing:
res = api.ReasonDisconnectRequired
}
return res, nil return res, nil
} }

View file

@ -17,11 +17,11 @@ const (
PhasesEnabled = "phasesEnabled" // enabled phases (1/3) PhasesEnabled = "phasesEnabled" // enabled phases (1/3)
PhasesActive = "phasesActive" // active phases as used by vehicle (1/2/3) PhasesActive = "phasesActive" // active phases as used by vehicle (1/2/3)
ChargerIcon = "chargerIcon" // charger icon for ui ChargerIcon = "chargerIcon" // charger icon for ui
ChargerFeature = "chargerFeature" // charger feature ChargerFeature = "chargerFeature" // charger feature
ChargerPhysicalPhases = "chargerPhysicalPhases" // charger phases ChargerPhysicalPhases = "chargerPhysicalPhases" // charger phases
ChargerPhases1p3p = "chargerPhases1p3p" // phase switcher (1p3p chargers) ChargerPhases1p3p = "chargerPhases1p3p" // phase switcher (1p3p chargers)
ChargerAwaitingAuthorization = "chargerAwaitingAuthorization" // charger awaiting authorization ChargerStatusReason = "chargerStatusReason" // either awaiting authorization or disconnect required
// loadpoint status // loadpoint status
Enabled = "enabled" // loadpoint enabled Enabled = "enabled" // loadpoint enabled

View file

@ -1676,7 +1676,7 @@ func (lp *Loadpoint) Update(sitePower float64, rates api.Rates, batteryBuffered,
if sr, ok := lp.charger.(api.StatusReasoner); ok && lp.GetStatus() == api.StatusB { if sr, ok := lp.charger.(api.StatusReasoner); ok && lp.GetStatus() == api.StatusB {
if r, err := sr.StatusReason(); err == nil { if r, err := sr.StatusReason(); err == nil {
lp.publish(keys.ChargerAwaitingAuthorization, r == api.ReasonWaitingForAuthorization) lp.publish(keys.ChargerStatusReason, r)
} else { } else {
lp.log.ERROR.Printf("charger status reason: %v", err) lp.log.ERROR.Printf("charger status reason: %v", err)
} }

View file

@ -541,6 +541,7 @@ cleanEnergyNextStart = "Saubere Energie in {duration}."
cleanEnergySet = "CO₂-Limit gesetzt." cleanEnergySet = "CO₂-Limit gesetzt."
climating = "Vorklimatisierung erkannt." climating = "Vorklimatisierung erkannt."
connected = "Verbunden." connected = "Verbunden."
disconnectRequired = "Vorgang abgebrochen. Erneut verbinden."
disconnected = "Nicht verbunden." disconnected = "Nicht verbunden."
finished = "Abgeschlossen." finished = "Abgeschlossen."
minCharge = "Mindestladung bis {soc}." minCharge = "Mindestladung bis {soc}."

View file

@ -539,6 +539,7 @@ cleanEnergyNextStart = "Clean energy in {duration}."
cleanEnergySet = "CO₂ limit set." cleanEnergySet = "CO₂ limit set."
climating = "Pre-conditioning detected." climating = "Pre-conditioning detected."
connected = "Connected." connected = "Connected."
disconnectRequired = "Session terminated. Please reconnect."
disconnected = "Disconnected." disconnected = "Disconnected."
finished = "Finished." finished = "Finished."
minCharge = "Minimum charging to {soc}." minCharge = "Minimum charging to {soc}."