Implemented a working mechanism for pausing and resuming a charging session
This commit is contained in:
parent
7d7cbf9cad
commit
e6f7b4fd4e
|
@ -55,9 +55,9 @@ contract.certificate.update.timespan = 14
|
|||
# SessionID
|
||||
#----------
|
||||
#
|
||||
# If this value is unequal to zero, then it represents a previously
|
||||
# paused V2G communication session
|
||||
session.id = 0
|
||||
# Hexadecimal string representing a byte array. If this value is unequal to "00", then it represents a
|
||||
# previously paused V2G communication session
|
||||
session.id = 00
|
||||
|
||||
|
||||
# Selected payment option
|
||||
|
@ -141,4 +141,4 @@ exi.codec = exificient
|
|||
# Used for the PreCharge target voltage. The present voltage indicated by the charging station in PreChargeRes can deviate from the present voltage
|
||||
# set in PreChargeReq by an EV-specific deviation factor. This value is given in percent.
|
||||
# Example: voltage.accuracy = 10 means: present voltage may deviate from target voltage by 10 percent in order to successfully stop PreCharge
|
||||
voltage.accuracy = 5
|
||||
voltage.accuracy = 5
|
|
@ -32,8 +32,10 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import com.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
|
||||
import com.v2gclarity.risev2g.shared.enumerations.CPStates;
|
||||
import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVChargeParameterType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingProfileType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVChargeParameterType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVErrorCodeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVPowerDeliveryParameterType;
|
||||
|
@ -63,21 +65,31 @@ public class DummyEVController implements IACEVController, IDCEVController {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PaymentOptionType getPaymentOption(PaymentOptionListType paymentOptionsOffered) {
|
||||
// Contract payment option may only be chosen if offered by SECC AND if communication is secured by TLS
|
||||
if (paymentOptionsOffered.getPaymentOption().contains(PaymentOptionType.CONTRACT)) {
|
||||
if (!getCommSessionContext().isTlsConnection()) {
|
||||
getLogger().warn("SECC offered CONTRACT based payment although no TLS connectionis used. Choosing EIM instead");
|
||||
return PaymentOptionType.EXTERNAL_PAYMENT;
|
||||
} else return PaymentOptionType.CONTRACT;
|
||||
} else return PaymentOptionType.EXTERNAL_PAYMENT;
|
||||
public PaymentOptionType getPaymentOption() {
|
||||
/*
|
||||
* The payment options offered by the SECC should probably be displayed on a HMI in the EV.
|
||||
* A request to the EVController should then be initiated here in order to let the user
|
||||
* choose which offered payment option to use.
|
||||
*
|
||||
* TODO check [V2G2-828] (selecting payment option related to state B, C)
|
||||
*/
|
||||
|
||||
// Set default to Plug & Charge
|
||||
return PaymentOptionType.CONTRACT;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EnergyTransferModeType getRequestedEnergyTransferMode() {
|
||||
return EnergyTransferModeType.AC_SINGLE_PHASE_CORE;
|
||||
// Set default to AC_THREE_PHASE_CORE. Should normally depend on type of cable plugged into the vehicle inlet
|
||||
EnergyTransferModeType requestedEnergyTransferMode = (EnergyTransferModeType) MiscUtils.getPropertyValue("energy.transfermode.requested");
|
||||
|
||||
if (requestedEnergyTransferMode == null)
|
||||
return EnergyTransferModeType.AC_THREE_PHASE_CORE;
|
||||
else
|
||||
return requestedEnergyTransferMode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JAXBElement<ACEVChargeParameterType> getACEVChargeParamter() {
|
||||
|
@ -320,6 +332,13 @@ public class DummyEVController implements IACEVController, IDCEVController {
|
|||
|
||||
return true;
|
||||
} else
|
||||
|
||||
/*
|
||||
* OPTIONAL:
|
||||
* If you want to trigger a pause of the charging session, then uncomment this line
|
||||
*/
|
||||
//getCommSessionContext().setChargingSession(ChargingSessionType.PAUSE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public interface IEVController {
|
|||
* RFID card or via Plug-and-Charge (PnC)
|
||||
* @return The payment option Contract or ExternalPayment
|
||||
*/
|
||||
public PaymentOptionType getPaymentOption(PaymentOptionListType paymentOptionsOffered);
|
||||
public PaymentOptionType getPaymentOption();
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,7 +30,7 @@ import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
|||
public class StartEVCC {
|
||||
|
||||
public static void main(String[] args) {
|
||||
MiscUtils.setV2gEntityConfig(GlobalValues.EVCC_CONFIG_PROPERTIES_PATH.toString());
|
||||
MiscUtils.loadProperties(GlobalValues.EVCC_CONFIG_PROPERTIES_PATH.toString());
|
||||
new V2GCommunicationSessionHandlerEVCC();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,14 @@ import com.v2gclarity.risev2g.shared.messageHandling.SendMessage;
|
|||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.V2GCommunicationSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.V2GTPMessage;
|
||||
import com.v2gclarity.risev2g.shared.utils.ByteUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.SecurityUtils.ContractCertificateStatus;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.AppProtocolType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.SupportedAppProtocolRes;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscoveryReqType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingProfileType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SAScheduleListType;
|
||||
|
@ -87,9 +90,8 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
* (saves some processing time)
|
||||
*/
|
||||
private ChargeParameterDiscoveryReqType chargeParameterDiscoveryReq;
|
||||
private boolean stopChargingRequested;
|
||||
private ChargingSessionType chargingSession;
|
||||
private boolean renegotiationRequested;
|
||||
private boolean pausingV2GCommSession;
|
||||
private ChargingProfileType chargingProfile;
|
||||
private ServiceListType offeredServices;
|
||||
private SelectedServiceListType selectedServices;
|
||||
|
@ -148,6 +150,9 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
|
||||
// Set default value for contract certificate status to UNKNOWN
|
||||
setContractCertStatus(ContractCertificateStatus.UNKNOWN);
|
||||
|
||||
// ChargingSessionType only takes enum values "Pause" and "Terminate". Therefore, set it to null at beginning of charging session
|
||||
setChargingSession(null);
|
||||
|
||||
getLogger().debug("\n*******************************************" +
|
||||
"\n* New V2G communication session initialized" +
|
||||
|
@ -231,12 +236,21 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
|
||||
|
||||
private void saveSessionProperties() {
|
||||
// TODO save respective parameters to properties file
|
||||
// According to [V2G2-740]
|
||||
MiscUtils.getProperties().setProperty("session.id", "" + ByteUtils.toHexString(getSessionID()));
|
||||
MiscUtils.getProperties().setProperty("authentication.mode", getSelectedPaymentOption().value());
|
||||
MiscUtils.getProperties().setProperty("energy.transfermode.requested", getRequestedEnergyTransferMode().value());
|
||||
|
||||
MiscUtils.storeProperties(GlobalValues.EVCC_CONFIG_PROPERTIES_PATH.toString());
|
||||
}
|
||||
|
||||
|
||||
private void deleteSessionProperties() {
|
||||
// TODO delete the respective parameters from properties file
|
||||
// Reset the session ID and the authentication mode
|
||||
MiscUtils.getProperties().setProperty("session.id", "00");
|
||||
MiscUtils.getProperties().setProperty("authentication.mode", "");
|
||||
|
||||
MiscUtils.storeProperties(GlobalValues.EVCC_CONFIG_PROPERTIES_PATH.toString());
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,13 +297,6 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
this.reactionToIncomingMessage = reactionToIncomingMessage;
|
||||
}
|
||||
|
||||
public boolean isStopChargingRequested() {
|
||||
return stopChargingRequested;
|
||||
}
|
||||
|
||||
public void setStopChargingRequested(boolean stopChargingRequested) {
|
||||
this.stopChargingRequested = stopChargingRequested;
|
||||
}
|
||||
|
||||
public boolean isRenegotiationRequested() {
|
||||
return renegotiationRequested;
|
||||
|
@ -299,13 +306,6 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
this.renegotiationRequested = renegotiationRequested;
|
||||
}
|
||||
|
||||
public boolean isPausingV2GCommSession() {
|
||||
return pausingV2GCommSession;
|
||||
}
|
||||
|
||||
public void setPausingV2GCommSession(boolean pausingV2GCommSession) {
|
||||
this.pausingV2GCommSession = pausingV2GCommSession;
|
||||
}
|
||||
|
||||
public long getEvseScheduleReceived() {
|
||||
return evseScheduleReceived;
|
||||
|
@ -508,4 +508,15 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
|
|||
public void setSentGenChallenge(byte[] sentGenChallenge) {
|
||||
this.sentGenChallenge = sentGenChallenge;
|
||||
}
|
||||
|
||||
|
||||
public ChargingSessionType getChargingSession() {
|
||||
return chargingSession;
|
||||
}
|
||||
|
||||
|
||||
public void setChargingSession(ChargingSessionType chargingSession) {
|
||||
this.chargingSession = chargingSession;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -454,28 +454,19 @@ public abstract class ClientState extends State {
|
|||
|
||||
|
||||
protected EnergyTransferModeType getRequestedEnergyTransferMode() {
|
||||
// Check if an EnergyTransferModeType has been requested in a previously paused session
|
||||
EnergyTransferModeType requestedEnergyTransferMode =
|
||||
(EnergyTransferModeType) MiscUtils.getPropertyValue("energy.transfermode.requested");
|
||||
EnergyTransferModeType requestedEnergyTransferMode = null;
|
||||
|
||||
if (requestedEnergyTransferMode == null) {
|
||||
// Check if an EnergyTransferModeType has been requested in a previously paused session
|
||||
if (getCommSessionContext().isOldSessionJoined())
|
||||
requestedEnergyTransferMode = (EnergyTransferModeType) MiscUtils.getPropertyValue("energy.transfermode.requested");
|
||||
|
||||
if (requestedEnergyTransferMode == null)
|
||||
requestedEnergyTransferMode = getCommSessionContext().getEvController().getRequestedEnergyTransferMode();
|
||||
getCommSessionContext().setRequestedEnergyTransferMode(requestedEnergyTransferMode);
|
||||
}
|
||||
|
||||
// We need to save the requested energy transfer mode in the session variable to be able to store in the properties file during pausing
|
||||
getCommSessionContext().setRequestedEnergyTransferMode(requestedEnergyTransferMode);
|
||||
|
||||
return requestedEnergyTransferMode;
|
||||
}
|
||||
|
||||
|
||||
protected PaymentOptionType getSelectedPaymentOption() {
|
||||
// Check if a PaymentOptionType has been requested in a previously paused session
|
||||
PaymentOptionType selectedPaymentOption = (PaymentOptionType) MiscUtils.getPropertyValue("authentication.mode");
|
||||
|
||||
if (selectedPaymentOption == null) {
|
||||
selectedPaymentOption = getCommSessionContext().getEvController().getPaymentOption(getCommSessionContext().getPaymentOptions());
|
||||
getCommSessionContext().setSelectedPaymentOption(selectedPaymentOption);
|
||||
}
|
||||
|
||||
return selectedPaymentOption;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import com.v2gclarity.risev2g.shared.utils.SecurityUtils;
|
|||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVSEChargeParameterType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscoveryResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVSEChargeParameterType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSENotificationType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSEProcessingType;
|
||||
|
@ -105,7 +106,7 @@ public class WaitForChargeParameterDiscoveryRes extends ClientState {
|
|||
|
||||
if (evseNotification.equals(EVSENotificationType.STOP_CHARGING)) {
|
||||
getLogger().debug("The EVSE requested to stop the charging process");
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP), V2GMessages.POWER_DELIVERY_RES);
|
||||
} else {
|
||||
|
@ -134,7 +135,23 @@ public class WaitForChargeParameterDiscoveryRes extends ClientState {
|
|||
// Save the list of SASchedules (saves the time of reception as well)
|
||||
getCommSessionContext().setSaSchedules(saSchedules);
|
||||
|
||||
if (getCommSessionContext().getEvController().getCPState().equals(CPStates.STATE_B)) {
|
||||
/*
|
||||
* The following states are possible (and will not raise the termination of a charging session):
|
||||
* - State B:
|
||||
* - In AC charging, when exchanging the first ChargeParameterDiscoveryReq/Res message pair, before the charging loop
|
||||
* was initiated
|
||||
* - State C:
|
||||
* - In DC charging, when exchanging the first ChargeParameterDiscoveryReq/Res message pair, before the charging loop
|
||||
* was initiated
|
||||
* - In AC charging, after the charging loop was initiated and a renegotiation was triggered
|
||||
*/
|
||||
if (getCommSessionContext().getEvController().getCPState().equals(CPStates.STATE_B) ||
|
||||
(getCommSessionContext().getEvController().getCPState().equals(CPStates.STATE_C) &&
|
||||
getCommSessionContext().isRenegotiationRequested())) {
|
||||
|
||||
// We need to reset the renegotiation trigger (in case of State C and a renegotiation was triggered)
|
||||
getCommSessionContext().setRenegotiationRequested(false);
|
||||
|
||||
if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("AC")) {
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.START), V2GMessages.POWER_DELIVERY_RES);
|
||||
} else if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
|||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.utils.SecurityUtils;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusReqType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.MeteringReceiptReqType;
|
||||
|
@ -94,7 +95,8 @@ public class WaitForChargingStatusRes extends ClientState {
|
|||
|
||||
switch (chargingStatusRes.getACEVSEStatus().getEVSENotification()) {
|
||||
case STOP_CHARGING:
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
@ -117,7 +119,13 @@ public class WaitForChargingStatusRes extends ClientState {
|
|||
return getSendMessage(chargingStatusReq, V2GMessages.CHARGING_STATUS_RES);
|
||||
}
|
||||
} else {
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
/* Check if the EV controller triggered a pause of a charging session.
|
||||
* If not, indicate a termination of the charging session. This will be
|
||||
* evaluated in the state WaitForPowerDeliveryRes
|
||||
*/
|
||||
if (getCommSessionContext().getChargingSession() == null)
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
|||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.utils.SecurityUtils;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusReqType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CurrentDemandResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVSEStatusType;
|
||||
|
@ -88,7 +89,8 @@ public class WaitForCurrentDemandRes extends ClientState {
|
|||
|
||||
switch ((EVSENotificationType) dcEVSEStatus.getEVSENotification()) {
|
||||
case STOP_CHARGING:
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
@ -110,7 +112,13 @@ public class WaitForCurrentDemandRes extends ClientState {
|
|||
return getSendMessage(getCurrentDemandReq(), V2GMessages.CURRENT_DEMAND_RES);
|
||||
}
|
||||
} else {
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
/* Check if the EV controller triggered a pause of a charging session.
|
||||
* If not, indicate a termination of the charging session. This will be
|
||||
* evaluated in the state WaitForPowerDeliveryRes
|
||||
*/
|
||||
if (getCommSessionContext().getChargingSession() == null)
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
|||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVSEStatusType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusReqType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVSEStatusType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSENotificationType;
|
||||
|
@ -65,7 +66,8 @@ public class WaitForMeteringReceiptRes extends ClientState {
|
|||
|
||||
switch (evseNotification) {
|
||||
case STOP_CHARGING:
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
@ -97,7 +99,6 @@ public class WaitForMeteringReceiptRes extends ClientState {
|
|||
return getSendMessage(getCurrentDemandReq(), V2GMessages.CURRENT_DEMAND_RES);
|
||||
}
|
||||
} else {
|
||||
getCommSessionContext().setStopChargingRequested(true);
|
||||
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.STOP),
|
||||
V2GMessages.POWER_DELIVERY_RES,
|
||||
" (ChargeProgress = STOP_CHARGING)");
|
||||
|
|
|
@ -66,12 +66,13 @@ public class WaitForPowerDeliveryRes extends ClientState {
|
|||
getCommSessionContext().setChangeToState(CPStates.STATE_B);
|
||||
}
|
||||
|
||||
getCommSessionContext().setRenegotiationRequested(false);
|
||||
return getSendMessage(getChargeParameterDiscoveryReq(), V2GMessages.CHARGE_PARAMETER_DISCOVERY_RES);
|
||||
} else if (getCommSessionContext().isStopChargingRequested()) {
|
||||
return getSendMessage(ChargingSessionType.TERMINATE, true);
|
||||
} else if (getCommSessionContext().isPausingV2GCommSession()) {
|
||||
return getSendMessage(ChargingSessionType.PAUSE, false);
|
||||
} else if (getCommSessionContext().getChargingSession() != null &&
|
||||
getCommSessionContext().getChargingSession() == ChargingSessionType.TERMINATE) {
|
||||
return getSendMessage(ChargingSessionType.TERMINATE);
|
||||
} else if (getCommSessionContext().getChargingSession() != null &&
|
||||
getCommSessionContext().getChargingSession() == ChargingSessionType.PAUSE) {
|
||||
return getSendMessage(ChargingSessionType.PAUSE);
|
||||
} else {
|
||||
if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("AC")) {
|
||||
ChargingStatusReqType chargingStatusReq = new ChargingStatusReqType();
|
||||
|
@ -86,7 +87,7 @@ public class WaitForPowerDeliveryRes extends ClientState {
|
|||
}
|
||||
|
||||
|
||||
private ReactionToIncomingMessage getSendMessage(ChargingSessionType chargingSessionType, boolean stopChargingRequested) {
|
||||
private ReactionToIncomingMessage getSendMessage(ChargingSessionType chargingSessionType) {
|
||||
if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
|
||||
// CP state B signaling BEFORE sending WeldingDetectionReq message in DC
|
||||
if (getCommSessionContext().getEvController().setCPState(CPStates.STATE_B)) {
|
||||
|
@ -100,10 +101,7 @@ public class WaitForPowerDeliveryRes extends ClientState {
|
|||
getCommSessionContext().getEvController().getCPState() +
|
||||
")");
|
||||
}
|
||||
} else {
|
||||
if (stopChargingRequested) getCommSessionContext().setStopChargingRequested(false);
|
||||
else getCommSessionContext().setPausingV2GCommSession(false);
|
||||
|
||||
} else {
|
||||
return getSendMessage(getSessionStopReq(chargingSessionType),
|
||||
V2GMessages.SESSION_STOP_RES, "(ChargingSession = " +
|
||||
chargingSessionType.toString() + ")");
|
||||
|
|
|
@ -28,9 +28,11 @@ import com.v2gclarity.risev2g.evcc.transportLayer.TLSClient;
|
|||
import com.v2gclarity.risev2g.shared.enumerations.V2GMessages;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.SecurityUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.SecurityUtils.ContractCertificateStatus;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionListType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SelectedServiceType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ServiceCategoryType;
|
||||
|
@ -60,7 +62,7 @@ public class WaitForServiceDiscoveryRes extends ClientState {
|
|||
*/
|
||||
getCommSessionContext().getServiceDetailsToBeRequested().clear(); // just to be sure
|
||||
|
||||
// Save offered charge service and optional value added services
|
||||
// Save the list containing information on all other services than charging services offered by the charging station
|
||||
getCommSessionContext().setOfferedServices(serviceDiscoveryRes.getServiceList());
|
||||
|
||||
if (serviceDiscoveryRes.getChargeService() != null) {
|
||||
|
@ -69,7 +71,6 @@ public class WaitForServiceDiscoveryRes extends ClientState {
|
|||
|
||||
if (serviceDiscoveryRes.getChargeService().getSupportedEnergyTransferMode()
|
||||
.getEnergyTransferMode().contains(requestedEnergyTransferMode)) {
|
||||
getCommSessionContext().setRequestedEnergyTransferMode(requestedEnergyTransferMode);
|
||||
getCommSessionContext().getOfferedServices().getService().add(serviceDiscoveryRes.getChargeService());
|
||||
addSelectedService(1, null); // Assumption: a charge service is always used
|
||||
} else {
|
||||
|
@ -77,16 +78,7 @@ public class WaitForServiceDiscoveryRes extends ClientState {
|
|||
}
|
||||
} else return new TerminateSession("No charge service available");
|
||||
|
||||
/*
|
||||
* The payment options offered by the SECC should probably be displayed on a HMI in the EV.
|
||||
* A request to the EVController should then be initiated here in order to let the user
|
||||
* choose which offered payment option to use.
|
||||
*
|
||||
* TODO check [V2G2-828] (selecting payment option related to state B, C)
|
||||
*/
|
||||
PaymentOptionType userPaymentOption =
|
||||
getCommSessionContext().getEvController().getPaymentOption(serviceDiscoveryRes.getPaymentOptionList());
|
||||
getCommSessionContext().setSelectedPaymentOption(userPaymentOption);
|
||||
getCommSessionContext().setSelectedPaymentOption(getSelectedPaymentOption(serviceDiscoveryRes.getPaymentOptionList()));
|
||||
|
||||
// Check for the usage of value added services (VAS)
|
||||
if (useVAS(serviceDiscoveryRes)) {
|
||||
|
@ -100,6 +92,41 @@ public class WaitForServiceDiscoveryRes extends ClientState {
|
|||
}
|
||||
|
||||
|
||||
protected PaymentOptionType getSelectedPaymentOption(PaymentOptionListType authenticationOptions) {
|
||||
/*
|
||||
* Note that although the type is called "PaymentOptionListType", it's not a list of payment options, but authorization options,
|
||||
* namely either Plug & Charge ("Contract") or external identification means (EIM) like an RFID card ("ExternalPayment"). This is
|
||||
* why the parameter for this function is called "authenticationOptions" for clarity.
|
||||
*/
|
||||
|
||||
PaymentOptionType selectedPaymentOption = null;
|
||||
|
||||
// Check if a PaymentOptionType has been requested in a previously paused session
|
||||
if (getCommSessionContext().isOldSessionJoined())
|
||||
selectedPaymentOption = (PaymentOptionType) MiscUtils.getPropertyValue("authentication.mode");
|
||||
|
||||
if (selectedPaymentOption == null)
|
||||
selectedPaymentOption = getCommSessionContext().getEvController().getPaymentOption();
|
||||
|
||||
// Contract payment option may only be chosen if offered by SECC AND if communication is secured by TLS
|
||||
if (selectedPaymentOption.equals(PaymentOptionType.CONTRACT) &&
|
||||
authenticationOptions.getPaymentOption().contains(PaymentOptionType.CONTRACT)) {
|
||||
|
||||
if (!getCommSessionContext().isTlsConnection()) {
|
||||
getLogger().warn("SECC offered 'Contract' based payment although no TLS connectionis used. Choosing 'ExternalPayment' instead");
|
||||
getCommSessionContext().setSelectedPaymentOption(PaymentOptionType.EXTERNAL_PAYMENT);
|
||||
return PaymentOptionType.EXTERNAL_PAYMENT;
|
||||
} else {
|
||||
getCommSessionContext().setSelectedPaymentOption(PaymentOptionType.CONTRACT);
|
||||
return PaymentOptionType.CONTRACT;
|
||||
}
|
||||
} else {
|
||||
getCommSessionContext().setSelectedPaymentOption(PaymentOptionType.EXTERNAL_PAYMENT);
|
||||
return PaymentOptionType.EXTERNAL_PAYMENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* According to [V2G2-422] a ServiceDetailsReq is needed in case VAS (value added services)
|
||||
* such as certificate installation/update are to be used and offered by the SECC.
|
||||
|
|
|
@ -47,14 +47,10 @@ public class WaitForSessionSetupRes extends ClientState {
|
|||
(SessionSetupResType) ((V2GMessage) message).getBody().getBodyElement().getValue();
|
||||
|
||||
if (sessionSetupRes.getResponseCode().equals(ResponseCodeType.OK_NEW_SESSION_ESTABLISHED)) {
|
||||
getCommSessionContext().setSessionID(receivedSessionID);
|
||||
getLogger().debug("Negotiated session ID is " + ByteUtils.toLongFromByteArray(receivedSessionID));
|
||||
getLogger().debug("Negotiated session ID is " + ByteUtils.toHexString(receivedSessionID));
|
||||
getCommSessionContext().setOldSessionJoined(false);
|
||||
getCommSessionContext().setEvseID(sessionSetupRes.getEVSEID());
|
||||
// EVSETimeStamp is optional
|
||||
if (sessionSetupRes.getEVSETimeStamp() != null) getCommSessionContext().setEvseTimeStamp(sessionSetupRes.getEVSETimeStamp());
|
||||
} else if (sessionSetupRes.getResponseCode().equals(ResponseCodeType.OK_OLD_SESSION_JOINED)) {
|
||||
getLogger().debug("Previous charging session joined (session ID = " + ByteUtils.toLongFromByteArray(receivedSessionID) + ")");
|
||||
getLogger().debug("Previous charging session joined (session ID = " + ByteUtils.toHexString(receivedSessionID) + ")");
|
||||
|
||||
/*
|
||||
* Mark that the old session was joined in order to resend
|
||||
|
@ -63,8 +59,6 @@ public class WaitForSessionSetupRes extends ClientState {
|
|||
* according to 8.4.2. Those values should be persisted in the properties file.
|
||||
*/
|
||||
getCommSessionContext().setOldSessionJoined(true);
|
||||
getCommSessionContext().setEvseID(sessionSetupRes.getEVSEID());
|
||||
getCommSessionContext().setEvseTimeStamp(sessionSetupRes.getEVSETimeStamp());
|
||||
} else {
|
||||
getCommSessionContext().setOldSessionJoined(false);
|
||||
getLogger().error("No negative response code received, but positive response code '" +
|
||||
|
@ -73,6 +67,12 @@ public class WaitForSessionSetupRes extends ClientState {
|
|||
return new TerminateSession("Positive response code invalid in state WaitForSessionSetupRes");
|
||||
}
|
||||
|
||||
getCommSessionContext().setSessionID(receivedSessionID);
|
||||
getCommSessionContext().setEvseID(sessionSetupRes.getEVSEID());
|
||||
// EVSETimeStamp is optional
|
||||
if (sessionSetupRes.getEVSETimeStamp() != null)
|
||||
getCommSessionContext().setEvseTimeStamp(sessionSetupRes.getEVSETimeStamp());
|
||||
|
||||
ServiceDiscoveryReqType serviceDiscoveryReq = new ServiceDiscoveryReqType();
|
||||
|
||||
/*
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
package com.v2gclarity.risev2g.evcc.states;
|
||||
|
||||
import com.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.PauseSession;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SessionStopResType;
|
||||
|
||||
public class WaitForSessionStopRes extends ClientState {
|
||||
|
@ -37,7 +39,11 @@ public class WaitForSessionStopRes extends ClientState {
|
|||
@Override
|
||||
public ReactionToIncomingMessage processIncomingMessage(Object message) {
|
||||
if (isIncomingMessageValid(message, SessionStopResType.class)) {
|
||||
return new TerminateSession("V2G communication session will be stopped successfully", true);
|
||||
if (getCommSessionContext().getChargingSession() != null &&
|
||||
getCommSessionContext().getChargingSession().equals(ChargingSessionType.PAUSE))
|
||||
return new PauseSession();
|
||||
else
|
||||
return new TerminateSession("V2G communication session will be stopped successfully", true);
|
||||
} else {
|
||||
return new TerminateSession("Incoming message raised an error");
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.v2gclarity.risev2g.shared.enumerations.V2GMessages;
|
|||
import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.TimeRestrictions;
|
||||
import com.v2gclarity.risev2g.shared.utils.ByteUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.AppProtocolType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.ResponseCodeType;
|
||||
|
@ -77,14 +78,18 @@ public class WaitForSupportedAppProtocolRes extends ClientState {
|
|||
/*
|
||||
* The session ID is taken from the properties file. If a previous charging session has been
|
||||
* paused, then the previously valid session ID has been written to the properties file
|
||||
* in order persist the value when the ISO/IEC 15118 controller is shut down for energy
|
||||
* in order persist the value when the ISO 15118 controller is shut down for energy
|
||||
* saving reasons.
|
||||
* The initial value for a completely new charging session must be 0.
|
||||
* The initial value for a completely new charging session must be 00.
|
||||
*/
|
||||
long sessionID = (long) MiscUtils.getPropertyValue("session.id");
|
||||
getCommSessionContext().setSessionID(
|
||||
getCommSessionContext().generateSessionIDFromValue(sessionID)
|
||||
);
|
||||
String sessionID = (String) MiscUtils.getPropertyValue("session.id");
|
||||
try {
|
||||
getCommSessionContext().setSessionID(ByteUtils.toByteArrayFromHexString(sessionID));
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().warn("Stored session ID '" + sessionID + "' contains illegal character(s) which are not hexadecimal. " +
|
||||
"Will reset session ID to '00'");
|
||||
getCommSessionContext().setSessionID(ByteUtils.toByteArrayFromHexString("00"));
|
||||
}
|
||||
} else {
|
||||
return new TerminateSession("No supported appProtocol found (positive response code received, " +
|
||||
"but no valid schemaID. Received schema ID is: " +
|
||||
|
|
|
@ -50,15 +50,13 @@ public class WaitForWeldingDetectionRes extends ClientState {
|
|||
* How to react on DCEVSEStatus values?
|
||||
*/
|
||||
|
||||
if (getCommSessionContext().isPausingV2GCommSession()) {
|
||||
getCommSessionContext().setPausingV2GCommSession(false);
|
||||
if (getCommSessionContext().getChargingSession() != null &&
|
||||
getCommSessionContext().getChargingSession() == ChargingSessionType.PAUSE) {
|
||||
|
||||
return getSendMessage(getSessionStopReq(ChargingSessionType.PAUSE),
|
||||
V2GMessages.SESSION_STOP_RES, "(ChargingSession = " +
|
||||
ChargingSessionType.PAUSE.toString() + ")");
|
||||
} else {
|
||||
getCommSessionContext().setStopChargingRequested(false);
|
||||
|
||||
} else {
|
||||
return getSendMessage(getSessionStopReq(ChargingSessionType.TERMINATE),
|
||||
V2GMessages.SESSION_STOP_RES, "(ChargingSession = " +
|
||||
ChargingSessionType.TERMINATE.toString() + ")");
|
||||
|
|
|
@ -73,12 +73,27 @@ public class DummyBackendInterface implements IBackendInterface {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SAScheduleListType getSAScheduleList(
|
||||
int maxEntriesSAScheduleTuple,
|
||||
long departureTime,
|
||||
HashMap<String, byte[]> xmlSignatureRefElements) {
|
||||
return getSAScheduleList(maxEntriesSAScheduleTuple, departureTime, xmlSignatureRefElements, (short) -1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SAScheduleListType getSAScheduleList(
|
||||
int maxEntriesSAScheduleTuple,
|
||||
long departureTime,
|
||||
HashMap<String, byte[]> xmlSignatureRefElements,
|
||||
short selectedSAScheduleTupleId) {
|
||||
/*
|
||||
* This is a static list of SASchedules. This means that we always offer the same list and ignore the
|
||||
* processing of the parameter selectedSAScheduleTupleId.
|
||||
*
|
||||
*
|
||||
* Some important requirements:
|
||||
*
|
||||
* 1. The sum of the individual time intervals described in the PMaxSchedule and
|
||||
|
|
|
@ -40,6 +40,7 @@ public interface IBackendInterface {
|
|||
*/
|
||||
public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext);
|
||||
|
||||
|
||||
/**
|
||||
* Provides a list of schedules coming from a secondary actor (SAScheduleList) with pMax values
|
||||
* and optional tariff incentives which shall influence the charging behaviour of the EV.
|
||||
|
@ -47,6 +48,7 @@ public interface IBackendInterface {
|
|||
* @param maxEntriesSAScheduleTuple The maximum number of PMaxEntries and SalesTariff entries allowed by EVCC
|
||||
* @param departureTime The departure time provided by the EV
|
||||
* @param xmlSignatureRefElements Signature reference parameter provided to put sales tariff IDs and sales tariffs in
|
||||
*
|
||||
* @return An SASchedulesType element with a list of secondary actor schedules
|
||||
*/
|
||||
public SAScheduleListType getSAScheduleList(
|
||||
|
@ -55,6 +57,27 @@ public interface IBackendInterface {
|
|||
HashMap<String, byte[]> xmlSignatureRefElements);
|
||||
|
||||
|
||||
/**
|
||||
* Provides a list of schedules coming from a secondary actor (SAScheduleList) with pMax values
|
||||
* and optional tariff incentives which shall influence the charging behaviour of the EV.
|
||||
*
|
||||
* The parameter selectedSAScheduleTupleId tells the backend to again offer a schedule with that ID
|
||||
* because the EVCC requested it in a previous charging session that has now been resumed after pausing.
|
||||
*
|
||||
* @param maxEntriesSAScheduleTuple The maximum number of PMaxEntries and SalesTariff entries allowed by EVCC
|
||||
* @param departureTime The departure time provided by the EV
|
||||
* @param xmlSignatureRefElements Signature reference parameter provided to put sales tariff IDs and sales tariffs in
|
||||
* @param selectedSAScheduleTupleId The SAScheduleTupleID which the EVCC chose in a previous charging session (optional)
|
||||
*
|
||||
* @return An SASchedulesType element with a list of secondary actor schedules
|
||||
*/
|
||||
public SAScheduleListType getSAScheduleList(
|
||||
int maxEntriesSAScheduleTuple,
|
||||
long departureTime,
|
||||
HashMap<String, byte[]> xmlSignatureRefElements,
|
||||
short selectedSAScheduleTupleId);
|
||||
|
||||
|
||||
/**
|
||||
* Provides a certificate chain coming from a secondary actor with the leaf certificate being
|
||||
* the contract certificate and possible intermediate certificates (Sub-CAs) included.
|
||||
|
|
|
@ -36,7 +36,7 @@ public class StartSECC {
|
|||
|
||||
public static void main(String[] args) {
|
||||
final Logger logger = LogManager.getLogger(StartSECC.class.getSimpleName());
|
||||
MiscUtils.setV2gEntityConfig(GlobalValues.SECC_CONFIG_PROPERTIES_PATH.toString());
|
||||
MiscUtils.loadProperties(GlobalValues.SECC_CONFIG_PROPERTIES_PATH.toString());
|
||||
|
||||
UDPServer udpServer = UDPServer.getInstance();
|
||||
TCPServer tcpServer = TCPServer.getInstance();
|
||||
|
|
|
@ -38,6 +38,7 @@ import com.v2gclarity.risev2g.secc.transportLayer.TLSServer;
|
|||
import com.v2gclarity.risev2g.secc.transportLayer.UDPServer;
|
||||
import com.v2gclarity.risev2g.shared.enumerations.GlobalValues;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.MessageHandler;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.PauseSession;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.V2GTPMessage;
|
||||
import com.v2gclarity.risev2g.shared.utils.ByteUtils;
|
||||
|
@ -97,13 +98,19 @@ public class V2GCommunicationSessionHandlerSECC implements Observer {
|
|||
* before the V2GCommunicationSessionSECC object is instantiated, otherwise it may lead to
|
||||
* race conditions.
|
||||
*/
|
||||
getLogger().debug("Resuming previous communication session ...");
|
||||
V2GCommunicationSessionSECC continuedSession = getV2gCommunicationSessions().get(ipAddress);
|
||||
|
||||
// Reset charging session state from previous session (namely ChargingSessionType.PAUSE) to avoid confusion in the algorithm
|
||||
continuedSession.setChargingSession(null);
|
||||
|
||||
continuedSession.setConnectionHandler((ConnectionHandler) obj);
|
||||
continuedSession.setTlsConnection((obs instanceof TLSServer) ? true : false);
|
||||
((ConnectionHandler) obj).addObserver(getV2gCommunicationSessions().get(ipAddress));
|
||||
|
||||
manageConnectionHandlers((ConnectionHandler) obj);
|
||||
} else {
|
||||
getLogger().debug("Initiating a new communication session ...");
|
||||
V2GCommunicationSessionSECC newSession = new V2GCommunicationSessionSECC((ConnectionHandler) obj);
|
||||
newSession.setTlsConnection((obs instanceof TLSServer) ? true : false);
|
||||
newSession.addObserver(this);
|
||||
|
@ -112,11 +119,14 @@ public class V2GCommunicationSessionHandlerSECC implements Observer {
|
|||
manageConnectionHandlers((ConnectionHandler) obj);
|
||||
}
|
||||
} else if (obs instanceof V2GCommunicationSessionSECC && obj instanceof TerminateSession) {
|
||||
// Remove the V2GCommunicationSessionSECC instance from the hashmap
|
||||
// Remove the V2GCommunicationSessionSECC instance from the hash map
|
||||
String ipAddress = ((V2GCommunicationSessionSECC) obs).getConnectionHandler().getAddress();
|
||||
getV2gCommunicationSessions().remove(ipAddress);
|
||||
|
||||
stopConnectionHandler(((V2GCommunicationSessionSECC) obs).getConnectionHandler());
|
||||
stopConnectionHandler(((V2GCommunicationSessionSECC) obs).getConnectionHandler(), false);
|
||||
} else if (obs instanceof V2GCommunicationSessionSECC && obj instanceof PauseSession) {
|
||||
// Stop the connection handler, but keep the V2GCommunicationSessionSECC instance in the hash map
|
||||
stopConnectionHandler(((V2GCommunicationSessionSECC) obs).getConnectionHandler(), true);
|
||||
} else {
|
||||
getLogger().warn("Notification received, but sending entity or received object not identifiable");
|
||||
}
|
||||
|
@ -184,7 +194,7 @@ public class V2GCommunicationSessionHandlerSECC implements Observer {
|
|||
* @param connectionHandler The ConnectionHandler whose socket is to be closed and whose thread
|
||||
* is to be interrupted.
|
||||
*/
|
||||
public void stopConnectionHandler(ConnectionHandler connectionHandler) {
|
||||
public void stopConnectionHandler(ConnectionHandler connectionHandler, boolean pausingSession) {
|
||||
if (getConnectionHandlerMap().containsKey(connectionHandler)) {
|
||||
// Close the socket
|
||||
connectionHandler.stop();
|
||||
|
@ -196,7 +206,9 @@ public class V2GCommunicationSessionHandlerSECC implements Observer {
|
|||
// Remove HashMap entry
|
||||
getConnectionHandlerMap().remove(connectionHandler);
|
||||
|
||||
getLogger().debug("Thread '" + connectionThread.getName() + "' has been interrupted and removed\n\n" );
|
||||
|
||||
getLogger().debug("Thread '" + connectionThread.getName() + "' has been interrupted and removed" +
|
||||
((pausingSession) ? ". Charging session is paused." : "") + "\n\n");
|
||||
} else {
|
||||
String address = connectionHandler.getAddress();
|
||||
int port = connectionHandler.getPort();
|
||||
|
|
|
@ -57,20 +57,24 @@ import com.v2gclarity.risev2g.secc.transportLayer.ConnectionHandler;
|
|||
import com.v2gclarity.risev2g.shared.enumerations.GlobalValues;
|
||||
import com.v2gclarity.risev2g.shared.enumerations.V2GMessages;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.ChangeProcessingState;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.PauseSession;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.SendMessage;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.V2GCommunicationSession;
|
||||
import com.v2gclarity.risev2g.shared.misc.V2GTPMessage;
|
||||
import com.v2gclarity.risev2g.shared.utils.ByteUtils;
|
||||
import com.v2gclarity.risev2g.shared.utils.MiscUtils;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.SupportedAppProtocolReq;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVSEStatusType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CertificateChainType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSENotificationType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.MessageHeaderType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.MeterInfoType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PMaxScheduleType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionListType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ResponseCodeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SAScheduleListType;
|
||||
|
@ -81,8 +85,7 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
|
||||
private short schemaID;
|
||||
private ACEVSEStatusType acEVSEStatus;
|
||||
private boolean stopV2GCommunicationSession;
|
||||
private boolean pauseV2GCommunicationSession;
|
||||
private ChargingSessionType chargingSession;
|
||||
private PMaxScheduleType pMaxSchedule;
|
||||
private short chosenSAScheduleTuple;
|
||||
private IACEVSEController acEvseController;
|
||||
|
@ -142,8 +145,8 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
getACEVSEStatus().setNotificationMaxDelay(0);
|
||||
getACEVSEStatus().setRCD(false);
|
||||
|
||||
setStopV2GCommunicationSession(false);
|
||||
setPauseV2GCommunicationSession(false);
|
||||
// Will be set only if a session is to be stopped or paused
|
||||
setChargingSession(null);
|
||||
|
||||
setOfferedServices(new ArrayList<ServiceType>());
|
||||
|
||||
|
@ -189,8 +192,11 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
// Check the outcome of the processIncomingMessage() of the respective state
|
||||
if (reactionToIncomingMessage instanceof SendMessage) {
|
||||
send((SendMessage) reactionToIncomingMessage);
|
||||
if (isStopV2GCommunicationSession()) {
|
||||
if (getChargingSession() != null && getChargingSession() == ChargingSessionType.TERMINATE)
|
||||
terminateSession("EVCC indicated request to stop the session or a FAILED response code was sent", true);
|
||||
|
||||
if (getChargingSession() != null && getChargingSession() == ChargingSessionType.PAUSE) {
|
||||
pauseSession(new PauseSession());
|
||||
}
|
||||
} else if (reactionToIncomingMessage instanceof ChangeProcessingState) {
|
||||
setCurrentState(((ChangeProcessingState) reactionToIncomingMessage).getNewState());
|
||||
|
@ -217,20 +223,22 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
*/
|
||||
public ResponseCodeType checkSessionID(MessageHeaderType header) {
|
||||
if (getCurrentState().equals(getStates().get(V2GMessages.SESSION_SETUP_REQ)) &&
|
||||
ByteUtils.toLongFromByteArray(header.getSessionID()) == 0L) {
|
||||
ByteUtils.toHexString(header.getSessionID()).equals("00")) {
|
||||
// EV wants to start a totally new charging session
|
||||
setSessionID(generateSessionIDRandomly());
|
||||
setOldSessionJoined(false);
|
||||
return ResponseCodeType.OK_NEW_SESSION_ESTABLISHED;
|
||||
} else if (getCurrentState().equals(getStates().get(V2GMessages.SESSION_SETUP_REQ)) &&
|
||||
header.getSessionID() == getSessionID()) {
|
||||
Arrays.equals(header.getSessionID(), getSessionID())) {
|
||||
// A charging pause has taken place and the EV wants to resume the old charging session
|
||||
setOldSessionJoined(true);
|
||||
return ResponseCodeType.OK_OLD_SESSION_JOINED;
|
||||
} else if (getCurrentState().equals(getStates().get(V2GMessages.SESSION_SETUP_REQ)) &&
|
||||
ByteUtils.toLongFromByteArray(header.getSessionID()) != 0L &&
|
||||
header.getSessionID() != getSessionID()) {
|
||||
!ByteUtils.toHexString(header.getSessionID()).equals("00") &&
|
||||
!Arrays.equals(header.getSessionID(), getSessionID())) {
|
||||
// Avoid a "FAILED_..." response code by generating a new SessionID in the response
|
||||
getLogger().warn("Presented session ID '" + ByteUtils.toHexString(header.getSessionID()) + "' does not match stored session ID '" +
|
||||
ByteUtils.toHexString(getSessionID()) + "'. Will reassign a new session ID");
|
||||
setSessionID(generateSessionIDRandomly());
|
||||
setOldSessionJoined(false);
|
||||
return ResponseCodeType.OK_NEW_SESSION_ESTABLISHED;
|
||||
|
@ -246,6 +254,27 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PaymentOptionListType getPaymentOptions() {
|
||||
ArrayList<PaymentOptionType> paymentOptions = new ArrayList<PaymentOptionType>();
|
||||
|
||||
if (isOldSessionJoined()) {
|
||||
paymentOptions.add(selectedPaymentOption);
|
||||
} else {
|
||||
paymentOptions.addAll((ArrayList<PaymentOptionType>) (MiscUtils.getPropertyValue("authentication.modes.supported")));
|
||||
}
|
||||
|
||||
// Contract-based payment may only be offered if TLS is used
|
||||
if (!isTlsConnection())
|
||||
paymentOptions.remove(PaymentOptionType.CONTRACT);
|
||||
|
||||
PaymentOptionListType paymentOptionList = new PaymentOptionListType();
|
||||
paymentOptionList.getPaymentOption().addAll(paymentOptions);
|
||||
|
||||
return paymentOptionList;
|
||||
}
|
||||
|
||||
|
||||
public void send(SendMessage sendMessage) {
|
||||
// Only EXI encoded messages will be sent here. Decide whether V2GMessage or SupportedAppProtocolRes
|
||||
byte[] payload = null;
|
||||
|
@ -284,24 +313,6 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
return acEVSEStatus;
|
||||
}
|
||||
|
||||
public boolean isStopV2GCommunicationSession() {
|
||||
return stopV2GCommunicationSession;
|
||||
}
|
||||
|
||||
public void setStopV2GCommunicationSession(boolean stopV2GCommunicationSession) {
|
||||
this.stopV2GCommunicationSession = stopV2GCommunicationSession;
|
||||
}
|
||||
|
||||
public boolean isPauseV2GCommunicationSession() {
|
||||
return pauseV2GCommunicationSession;
|
||||
}
|
||||
|
||||
|
||||
public void setPauseV2GCommunicationSession(boolean pauseV2GCommunicationSession) {
|
||||
this.pauseV2GCommunicationSession = pauseV2GCommunicationSession;
|
||||
}
|
||||
|
||||
|
||||
public PMaxScheduleType getPMaxSchedule() {
|
||||
return pMaxSchedule;
|
||||
}
|
||||
|
@ -475,4 +486,14 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
|
|||
public void setChargeProgressStarted(boolean chargeProgressStarted) {
|
||||
this.chargeProgressStarted = chargeProgressStarted;
|
||||
}
|
||||
|
||||
|
||||
public ChargingSessionType getChargingSession() {
|
||||
return chargingSession;
|
||||
}
|
||||
|
||||
|
||||
public void setChargingSession(ChargingSessionType chargingSession) {
|
||||
this.chargingSession = chargingSession;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CertificateChainType;
|
|||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CertificateInstallationResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CertificateUpdateResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscoveryResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusResType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ContractSignatureEncryptedPrivateKeyType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CurrentDemandResType;
|
||||
|
@ -167,7 +168,7 @@ public abstract class ServerState extends State {
|
|||
|
||||
if (!responseCode.value().startsWith("OK")) {
|
||||
getLogger().error("Response code '" + responseCode.value() + "' will be sent.");
|
||||
getCommSessionContext().setStopV2GCommunicationSession(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
}
|
||||
|
||||
return getSendMessage(message, nextExpectedMessage, "", timeout);
|
||||
|
@ -181,7 +182,7 @@ public abstract class ServerState extends State {
|
|||
|
||||
if (!responseCode.value().substring(0, 2).toUpperCase().equals("OK")) {
|
||||
getLogger().error("Response code '" + responseCode.value() + "' will be sent.");
|
||||
getCommSessionContext().setStopV2GCommunicationSession(true);
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
}
|
||||
|
||||
getLogger().debug("Preparing to send " + messageName);
|
||||
|
|
|
@ -40,6 +40,7 @@ import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscovery
|
|||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVChargeParameterType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSEProcessingType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.IsolationLevelType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ResponseCodeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SAScheduleListType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.V2GMessage;
|
||||
|
@ -80,12 +81,22 @@ public class WaitForChargeParameterDiscoveryReq extends ServerState {
|
|||
|
||||
Long departureTime = chargeParameterDiscoveryReq.getEVChargeParameter().getValue().getDepartureTime();
|
||||
|
||||
getCommSessionContext().setSaSchedules(
|
||||
getCommSessionContext().getBackendInterface().getSAScheduleList(
|
||||
maxEntriesSAScheduleTuple,
|
||||
(departureTime != null) ? departureTime.longValue() : 0,
|
||||
getXMLSignatureRefElements())
|
||||
);
|
||||
if (getCommSessionContext().isOldSessionJoined()) {
|
||||
getCommSessionContext().setSaSchedules(
|
||||
getCommSessionContext().getBackendInterface().getSAScheduleList(
|
||||
maxEntriesSAScheduleTuple,
|
||||
(departureTime != null) ? departureTime.longValue() : 0,
|
||||
getXMLSignatureRefElements(),
|
||||
getCommSessionContext().getChosenSAScheduleTuple())
|
||||
);
|
||||
} else {
|
||||
getCommSessionContext().setSaSchedules(
|
||||
getCommSessionContext().getBackendInterface().getSAScheduleList(
|
||||
maxEntriesSAScheduleTuple,
|
||||
(departureTime != null) ? departureTime.longValue() : 0,
|
||||
getXMLSignatureRefElements())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO An integration to a backend system which provides the SalesTariff would be needed here
|
||||
|
|
|
@ -65,10 +65,6 @@ public class WaitForPowerDeliveryReq extends ServerState {
|
|||
if (isResponseCodeOK(powerDeliveryReq)) {
|
||||
getCommSessionContext().setChosenSAScheduleTuple(powerDeliveryReq.getSAScheduleTupleID());
|
||||
|
||||
// For debugging purposes, log the ChargeProgress value
|
||||
getLogger().debug("ChargeProgress of PowerDeliveryReq set to '" +
|
||||
powerDeliveryReq.getChargeProgress().toString() + "'");
|
||||
|
||||
// TODO regard [V2G2-866]
|
||||
|
||||
setEVSEStatus(powerDeliveryRes);
|
||||
|
@ -114,8 +110,9 @@ public class WaitForPowerDeliveryReq extends ServerState {
|
|||
public boolean isResponseCodeOK(PowerDeliveryReqType powerDeliveryReq) {
|
||||
SAScheduleTupleType chosenSASchedule = getChosenSASCheduleTuple(powerDeliveryReq.getSAScheduleTupleID());
|
||||
|
||||
// This debug message is helpful to determine why the EV might not send a ChargingProfile (parameter is optional and should only be left out if ChargeProgress is set to Stop)
|
||||
getLogger().debug("ChargeProgress is set to " + powerDeliveryReq.getChargeProgress());
|
||||
// This debug message is helpful to determine why the EV might not send a ChargingProfile
|
||||
// (parameter is optional and should only be left out if ChargeProgress is set to Stop)
|
||||
getLogger().debug("ChargeProgress of PowerDeliveryReq set to '" + powerDeliveryReq.getChargeProgress().toString() + "'");
|
||||
|
||||
if (powerDeliveryReq.getChargeProgress().equals(ChargeProgressType.RENEGOTIATE) &&
|
||||
!getCommSessionContext().isChargeProgressStarted()) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.v2gclarity.risev2g.secc.session.V2GCommunicationSessionSECC;
|
|||
import com.v2gclarity.risev2g.shared.enumerations.V2GMessages;
|
||||
import com.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.BodyBaseType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentServiceSelectionReqType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ResponseCodeType;
|
||||
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SessionStopReqType;
|
||||
|
@ -51,18 +52,26 @@ public class WaitForSessionStopReq extends ServerState {
|
|||
|
||||
getLogger().info("EV indicated to " + sessionStopReq.getChargingSession() + " the charging session");
|
||||
|
||||
getCommSessionContext().setStopV2GCommunicationSession(true);
|
||||
if (sessionStopReq.getChargingSession() == ChargingSessionType.TERMINATE) {
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
return getSendMessage(sessionStopRes, V2GMessages.NONE, sessionStopRes.getResponseCode());
|
||||
} else {
|
||||
// EV indicated to pause the charging session. Next expected request message is SupportedAppProtocolReq
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.PAUSE);
|
||||
return getSendMessage(sessionStopRes, V2GMessages.SUPPORTED_APP_PROTOCOL_REQ, sessionStopRes.getResponseCode());
|
||||
}
|
||||
} else {
|
||||
getCommSessionContext().setChargingSession(ChargingSessionType.TERMINATE);
|
||||
|
||||
if (sessionStopRes.getResponseCode().equals(ResponseCodeType.FAILED_SEQUENCE_ERROR)) {
|
||||
BodyBaseType responseMessage = getSequenceErrorResMessage(new SessionStopResType(), message);
|
||||
|
||||
return getSendMessage(responseMessage, V2GMessages.NONE, sessionStopRes.getResponseCode());
|
||||
} else {
|
||||
setMandatoryFieldsForFailedRes(sessionStopRes, sessionStopRes.getResponseCode());
|
||||
return getSendMessage(sessionStopRes, V2GMessages.NONE, sessionStopRes.getResponseCode());
|
||||
}
|
||||
}
|
||||
|
||||
return getSendMessage(sessionStopRes, V2GMessages.NONE, sessionStopRes.getResponseCode());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,16 +60,7 @@ public abstract class V2GCommunicationSession extends Observable {
|
|||
setSessionID(null);
|
||||
setV2gTpMessage(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a session ID (with length of 8 bytes) from a given long value.
|
||||
* @param The long value representing a session ID (either 0 or a previously stored session ID)
|
||||
* @return The byte array representation of the provided session ID
|
||||
*/
|
||||
public byte[] generateSessionIDFromValue(long fromValue) {
|
||||
return ByteUtils.toByteArrayFromLong(fromValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates randomly a new session ID (with length of 8 bytes) and takes care that the newly generated
|
||||
|
@ -87,8 +78,7 @@ public abstract class V2GCommunicationSession extends Observable {
|
|||
}
|
||||
|
||||
protected void pauseSession(PauseSession pauseObject) {
|
||||
getLogger().info("Pausing"
|
||||
+ " V2G communication session");
|
||||
getLogger().info("Pausing V2G communication session");
|
||||
setChanged();
|
||||
notifyObservers(pauseObject);
|
||||
}
|
||||
|
@ -126,25 +116,6 @@ public abstract class V2GCommunicationSession extends Observable {
|
|||
}
|
||||
|
||||
|
||||
public PaymentOptionListType getPaymentOptions() {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<PaymentOptionType> paymentOptions = (ArrayList<PaymentOptionType>) (MiscUtils.getPropertyValue("authentication.modes.supported"));
|
||||
|
||||
if (paymentOptions == null) {
|
||||
paymentOptions = new ArrayList<PaymentOptionType>();
|
||||
}
|
||||
|
||||
// Contract-based payment may only be offered if TLS is used
|
||||
if (!isTlsConnection())
|
||||
paymentOptions.remove(PaymentOptionType.CONTRACT);
|
||||
|
||||
PaymentOptionListType paymentOptionList = new PaymentOptionListType();
|
||||
paymentOptionList.getPaymentOption().addAll(paymentOptions);
|
||||
|
||||
return paymentOptionList;
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<EnergyTransferModeType> getSupportedEnergyTransferModes() {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<EnergyTransferModeType> energyTransferModes =
|
||||
|
@ -199,10 +170,9 @@ public abstract class V2GCommunicationSession extends Observable {
|
|||
|
||||
public void setSessionID(byte[] sessionID) {
|
||||
if (sessionID == null) {
|
||||
sessionID = generateSessionIDFromValue(0L);
|
||||
sessionID = ByteUtils.toByteArrayFromHexString("00");
|
||||
}
|
||||
this.sessionID = sessionID;
|
||||
MiscUtils.getV2gEntityConfig().setProperty("session.id", String.valueOf(ByteUtils.toLongFromByteArray(sessionID)));
|
||||
}
|
||||
|
||||
public V2GTPMessage getV2gTpMessage() {
|
||||
|
|
|
@ -43,7 +43,7 @@ public abstract class V2GImplementationFactory {
|
|||
*/
|
||||
protected static <T> T buildFromProperties(String propertyName, Class<T> cls) {
|
||||
try {
|
||||
String className = MiscUtils.getV2gEntityConfig().getProperty(propertyName);
|
||||
String className = MiscUtils.getProperties().getProperty(propertyName);
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -67,9 +67,11 @@ public final class ByteUtils {
|
|||
* representing the octet code. For example, '0FB7' is a hex encoding for the
|
||||
* 16-bit integer 4023 (whose binary representation is 111110110111)."
|
||||
* @return A byte array representing the hexadecimal string
|
||||
* @throws IllegalArgumentException Passes on the IllegalArgumentException from the method DatatypeConverter.parseHexBinary()
|
||||
* so that the caller can appropriately handle the execption
|
||||
*/
|
||||
public static byte[] toByteArrayFromHexString(String s) {
|
||||
return DatatypeConverter.parseHexBinary(s);
|
||||
public static byte[] toByteArrayFromHexString(String s) throws IllegalArgumentException {
|
||||
return DatatypeConverter.parseHexBinary(s);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@ package com.v2gclarity.risev2g.shared.utils;
|
|||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
@ -47,7 +48,7 @@ public final class MiscUtils {
|
|||
|
||||
static Logger logger = LogManager.getLogger(MiscUtils.class.getSimpleName());
|
||||
static V2GMessages[] messageTypes = V2GMessages.values();
|
||||
static Properties v2gEntityConfig;
|
||||
static Properties properties;
|
||||
|
||||
public static Logger getLogger() {
|
||||
return logger;
|
||||
|
@ -131,34 +132,27 @@ public final class MiscUtils {
|
|||
* in this method. The return value differs depending on the key. Therefore, the return value
|
||||
* is given as an Object, which again must be casted to the matching type when using this method.
|
||||
*
|
||||
* @param propertyName The key string written in the respective properties file of each V2G entity (EV or EVSE)
|
||||
* @param propertyKey The key string written in the respective properties file of each V2G entity (EV or EVSE)
|
||||
* @return An Object holding the data structure fitting for the key (e.g. an Enum value, a Boolean,
|
||||
* a collection, ...)
|
||||
*/
|
||||
public static Object getPropertyValue(String propertyName) {
|
||||
public static Object getPropertyValue(String propertyKey) {
|
||||
Object returnValue = null;
|
||||
String propertyValue = "";
|
||||
|
||||
try {
|
||||
propertyValue = getV2gEntityConfig().getProperty(propertyName).replaceAll("\\s", "");
|
||||
propertyValue = getProperties().getProperty(propertyKey).replaceAll("\\s", "");
|
||||
} catch (NullPointerException e) {
|
||||
getLogger().warn("No entry found in the properties file for property '" + propertyName + "'", e);
|
||||
getLogger().warn("No entry found in the properties file for property '" + propertyKey + "'", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (propertyName) {
|
||||
switch (propertyKey) {
|
||||
case "network.interface": // EV + EVSE property
|
||||
returnValue = propertyValue;
|
||||
break;
|
||||
case "session.id": // EV property
|
||||
try {
|
||||
returnValue = Long.parseLong(propertyValue);
|
||||
} catch (NumberFormatException e) {
|
||||
getLogger().warn("SessionID '" + propertyValue + "' not supported. " +
|
||||
"Setting default value to 0.", e);
|
||||
getV2gEntityConfig().setProperty("session.id", "0");
|
||||
returnValue = 0L;
|
||||
}
|
||||
returnValue = propertyValue; // a hexadecimal string representing a byte array
|
||||
break;
|
||||
case "energy.transfermodes.supported": // EVSE property
|
||||
String energyTransferMode = "";
|
||||
|
@ -170,7 +164,7 @@ public final class MiscUtils {
|
|||
try {
|
||||
supportedEnergyTransferModeType.getEnergyTransferMode().add(EnergyTransferModeType.fromValue(energyTransferMode));
|
||||
} catch (IllegalArgumentException e){
|
||||
getLogger().warn("EnergyTransferModeType '" + energyTransferMode + "' not supported");
|
||||
getLogger().warn("EnergyTransferModeType '" + energyTransferMode + "' listed in properties file is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,11 +172,10 @@ public final class MiscUtils {
|
|||
break;
|
||||
case "energy.transfermode.requested": // EV property
|
||||
try {
|
||||
if (!propertyValue.equals("")) returnValue = EnergyTransferModeType.fromValue(propertyValue);
|
||||
else return null;
|
||||
if (!propertyValue.equals(""))
|
||||
returnValue = EnergyTransferModeType.fromValue(propertyValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().warn("EnergyTransferModeType '" + propertyValue + "' not supported");
|
||||
return null;
|
||||
getLogger().warn("EnergyTransferModeType '" + propertyValue + "' listed in properties file is not supported");
|
||||
}
|
||||
break;
|
||||
case "tls": // EV property (with this code, TLS is always supported on EVSE side)
|
||||
|
@ -193,19 +186,18 @@ public final class MiscUtils {
|
|||
try {
|
||||
returnValue = Integer.parseInt(propertyValue);
|
||||
} catch (NumberFormatException e) {
|
||||
getLogger().warn("ContractCertificateUpdateTimespan '" + propertyValue + "' not supported. " +
|
||||
getLogger().warn("ContractCertificateUpdateTimespan '" + propertyValue + "' listed in properties file is not supported. " +
|
||||
"Setting default value to 14.", e);
|
||||
getV2gEntityConfig().setProperty("contract.certificate.update.timespan", "14");
|
||||
getProperties().setProperty("contract.certificate.update.timespan", "14");
|
||||
returnValue = 14;
|
||||
}
|
||||
break;
|
||||
case "authentication.mode": // EV property
|
||||
try {
|
||||
if (!propertyValue.equals("")) returnValue = PaymentOptionType.fromValue(propertyValue);
|
||||
else return null;
|
||||
if (!propertyValue.equals(""))
|
||||
returnValue = PaymentOptionType.fromValue(propertyValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().warn("PaymentOptionType '" + propertyValue + "' not supported");
|
||||
return null;
|
||||
getLogger().warn("PaymentOptionType '" + propertyValue + "' listed in properties file is not supported");
|
||||
}
|
||||
break;
|
||||
case "authentication.modes.supported": // EVSE property
|
||||
|
@ -219,7 +211,7 @@ public final class MiscUtils {
|
|||
try {
|
||||
paymentOptionsList.add(PaymentOptionType.fromValue(option));
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().warn("PaymentOptionType '" + option + "' not supported");
|
||||
getLogger().warn("PaymentOptionType '" + option + "' listed in properties file is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,14 +243,14 @@ public final class MiscUtils {
|
|||
try {
|
||||
returnValue = Integer.parseInt(propertyValue);
|
||||
} catch (NumberFormatException e) {
|
||||
getLogger().warn("Voltage accuracy '" + propertyValue + "' not supported. " +
|
||||
getLogger().warn("Voltage accuracy '" + propertyValue + "' listed in properties file is not supported. " +
|
||||
"Setting default value to 5.", e);
|
||||
getV2gEntityConfig().setProperty("voltage.accuracy", "5");
|
||||
getProperties().setProperty("voltage.accuracy", "5");
|
||||
returnValue = 5;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
getLogger().error("No property with name '" + propertyName + "' found");
|
||||
getLogger().error("No property with name '" + propertyKey + "' found");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
|
@ -273,8 +265,8 @@ public final class MiscUtils {
|
|||
* @return The Properties object containing the (key, value)-pairs of the respective properties
|
||||
* file for the respective V2G entity (EVCC or SECC)
|
||||
*/
|
||||
public static Properties getV2gEntityConfig() {
|
||||
return v2gEntityConfig;
|
||||
public static Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
|
@ -287,13 +279,12 @@ public final class MiscUtils {
|
|||
* @param propertiesFileLocation The location of the properties file
|
||||
* @return True, if the properties file could be loaded successfully.
|
||||
*/
|
||||
public static boolean setV2gEntityConfig(String propertiesFileLocation) {
|
||||
Properties properties = new Properties();
|
||||
public static boolean loadProperties(String propertiesFileLocation) {
|
||||
properties = new Properties();
|
||||
|
||||
try {
|
||||
FileInputStream config = new FileInputStream(propertiesFileLocation);
|
||||
properties.load(config);
|
||||
v2gEntityConfig = properties;
|
||||
config.close();
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
|
@ -306,4 +297,25 @@ public final class MiscUtils {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the current properties into the properties file
|
||||
*
|
||||
*/
|
||||
public static void storeProperties(String propertiesFileLocation) {
|
||||
try {
|
||||
FileOutputStream configFile = new FileOutputStream(propertiesFileLocation);
|
||||
|
||||
getProperties().store(configFile, "");
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// getV2gEntityConfig().store(out, "");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue