Skip to content

Commit

Permalink
- TargetCurrent in DummyEVController, used in PreChargeReq message, w…
Browse files Browse the repository at this point in the history
…as set to 2A to comply to IEC 61851-23

- The necessary change from State C to State B during a renegotiation in DC charging is now correctly implemented
- Added the EV setting "voltage.accuracy" to allow for a percentage of deviation from the target current in PreCharge
  • Loading branch information
Marc Mültin committed Apr 25, 2018
1 parent 0e4b838 commit cba5e04
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 36 deletions.
9 changes: 9 additions & 0 deletions RISE-V2G-EVCC/EVCCConfig.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,12 @@ signature.verification.showlog = true
# - open_exi
# If no correct value is provided here, 'exificient' will be used
exi.codec = exificient


# Voltage accuracy
#----------
#
# 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
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public PhysicalValueType getTargetCurrent() {
PhysicalValueType targetCurrent = new PhysicalValueType();
targetCurrent.setMultiplier(new Byte("0"));
targetCurrent.setUnit(UnitSymbolType.A);
targetCurrent.setValue((short) 32);
targetCurrent.setValue((short) 2); // according to IEC 61851-23, this value should be limited to 2A as it seems (see https://github.com/V2GClarity/RISE-V2G/issues/20)

return targetCurrent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
V2GMessages.POWER_DELIVERY_RES,
" (ChargeProgress = STOP_CHARGING)");
case RE_NEGOTIATION:
getCommSessionContext().setRenegotiationRequested(true);
return getSendMessage(getPowerDeliveryReq(ChargeProgressType.RENEGOTIATE),
V2GMessages.POWER_DELIVERY_RES,
" (ChargeProgress = RE_NEGOTIATION)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
*/

if (getCommSessionContext().isRenegotiationRequested()) {
// In DC charging, we need to switch to state B during renegotiation because we need to go through CableCheckReq and PreChargeReq again for which state B is required
if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
getCommSessionContext().setChangeToState(CPStates.STATE_B);
}

getCommSessionContext().setRenegotiationRequested(false);
return getSendMessage(getChargeParameterDiscoveryReq(), V2GMessages.CHARGE_PARAMETER_DISCOVERY_RES);
} else if (getCommSessionContext().isStopChargingRequested()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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.MiscUtils;
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PreChargeReqType;
import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PreChargeResType;
Expand All @@ -55,7 +56,10 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
double targetVoltage = dcEvController.getTargetVoltage().getValue() * Math.pow(10, dcEvController.getTargetVoltage().getMultiplier());
double presentVoltage = preChargeRes.getEVSEPresentVoltage().getValue() * Math.pow(10, preChargeRes.getEVSEPresentVoltage().getMultiplier());

if (targetVoltage == presentVoltage) {
// Each EV has an EV-specific allowed deviation when measuring a target voltage
int voltageAccuracy = (int) MiscUtils.getPropertyValue("voltage.accuracy");

if (presentVoltage >= targetVoltage * (1 - voltageAccuracy / 100) && presentVoltage <= targetVoltage * (1 + voltageAccuracy / 100)) {
getCommSessionContext().setOngoingTimerActive(false);
getCommSessionContext().setOngoingTimer(0L);

Expand All @@ -67,6 +71,7 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
if (elapsedTimeInMs > TimeRestrictions.V2G_EVCC_PRE_CHARGE_TIMEOUT)
return new TerminateSession("PreCharge timer timed out for PreChargeReq");
else {
getLogger().debug("Target voltage of " + targetVoltage + " V not yet reached. Present voltage at EVSE is " + presentVoltage);
PreChargeReqType preChargeReq = new PreChargeReqType();
preChargeReq.setDCEVStatus(dcEvController.getDCEVStatus());
preChargeReq.setEVTargetCurrent(dcEvController.getTargetCurrent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
getCommSessionContext().getOfferedServices().getService().add(serviceDiscoveryRes.getChargeService());
addSelectedService(1, null); // Assumption: a charge service is always used
} else {
return new TerminateSession("Offered EnergyTransferModes not compatible with the requested one");
return new TerminateSession("Offered EnergyTransferModes not compatible with the requested one, which is " + requestedEnergyTransferMode.toString());
}
} else return new TerminateSession("No charge service available");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public DummyBackendInterface(V2GCommunicationSessionSECC commSessionContext) {
*/
ECPrivateKey privateKey = SecurityUtils.getPrivateKey("./moSubCA2.pkcs8.der");
if (privateKey == null)
getLogger().error("No private key available from MO Sub-CA 2 PKCS#8 file");
getLogger().warn("No private key available from MO Sub-CA 2 PKCS#8 file. Signing a SalesTariff will therefore not be possible");
else
setMoSubCA2PrivateKey(privateKey);

Expand Down Expand Up @@ -152,7 +152,7 @@ public SAScheduleListType getSAScheduleList(
SAScheduleTupleType saScheduleTuple = new SAScheduleTupleType();
saScheduleTuple.setSAScheduleTupleID((short) 1);
saScheduleTuple.setPMaxSchedule(pMaxSchedule);
saScheduleTuple.setSalesTariff(salesTariff);
saScheduleTuple.setSalesTariff(salesTariff);

SAScheduleListType saScheduleList = new SAScheduleListType();
saScheduleList.getSAScheduleTuple().add(saScheduleTuple);
Expand Down Expand Up @@ -235,6 +235,7 @@ public CertificateChainType getContractCertificateChain(CertificateChainType old
*/
ArrayList<EMAIDType> authorizedEMAIDs = new ArrayList<EMAIDType>();

// This is a list of EMAIDs used for testing purposes, like a whitelist
EMAIDType authorizedEMAID1 = new EMAIDType();
authorizedEMAID1.setId("id1");
authorizedEMAID1.setValue("DE1ABCD2EF357A");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public SAScheduleListType getSAScheduleList(
* Provides a certificate chain coming from a secondary actor with the leaf certificate being
* the contract certificate and possible intermediate certificates (Sub-CAs) included.
*
* This interface is to be used for the CertificateUpdate
*
* @param oldContractCertificateChain The to-be-updated contract certificate chain
* @return Certificate chain for contract certificate
*/
Expand All @@ -61,6 +63,8 @@ public SAScheduleListType getSAScheduleList(
* Provides a certificate chain coming from a secondary actor with the leaf certificate being
* the contract certificate and possible intermediate certificates (Sub-CAs) included.
*
* This interface is to be used for the CertificateInstallation
*
* @param oemProvisioningCert The OEM provisioning certificate
* @return Certificate chain for contract certificate
*/
Expand All @@ -69,6 +73,7 @@ public SAScheduleListType getSAScheduleList(

/**
* Provides the private key belonging to the contract certificate.
*
* @return PrivateKey of the contract certificate
*/
public ECPrivateKey getContractCertificatePrivateKey();
Expand All @@ -77,20 +82,23 @@ public SAScheduleListType getSAScheduleList(
/**
* Provides a certificate chain coming from a secondary actor with the leaf certificate being
* the provisioning certificate and possible intermediate certificates (sub CAs) included.
*
* @return Certificate chain for provisioning certificate
*/
public CertificateChainType getCPSCertificateChain();


/**
* Provides the private key belonging to the SA provisioning certificate.
*
* @return PrivateKey of the SA provisioning certificate
*/
public ECPrivateKey getCPSLeafPrivateKey();


/**
* Provides the private key belonging to the MO Sub-CA 2 certificate (signature of SalesTariff).
*
* @return PrivateKey of the MO Sub-CA 2 certificate
*/
public ECPrivateKey getMOSubCA2PrivateKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,6 @@ public ACEVSEStatusType getACEVSEStatus(EVSENotificationType notification) {
}


public V2GCommunicationSessionSECC getCommSessionContext() {
return commSessionContext;
}


public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext) {
this.commSessionContext = commSessionContext;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ public ReactionToIncomingMessage processIncomingMessage(Object message) {
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());

if (powerDeliveryReq.getChargeProgress().equals(ChargeProgressType.RENEGOTIATE) &&
!getCommSessionContext().isChargeProgressStarted()) {
getLogger().error("EVCC wants to renegotiate, but charge progress has not started yet (no "
Expand Down Expand Up @@ -171,7 +174,8 @@ public boolean isResponseCodeOK(PowerDeliveryReqType powerDeliveryReq) {


protected void setEVSEStatus(PowerDeliveryResType powerDeliveryRes) {
if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("AC")) {
// In case the SECC received a PowerDeliveryReq before a PaymentServiceSelectionReq, the field requestedEnergyTransferMode will be null. So we need to check for it.
if (getCommSessionContext().getRequestedEnergyTransferMode() != null && getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("AC")) {
/*
* The MiscUtils method getJAXBElement() cannot be used here because of the difference in the
* class name (ACEVSEStatus) and the name in the XSD (AC_EVSEStatus)
Expand All @@ -180,7 +184,7 @@ protected void setEVSEStatus(PowerDeliveryResType powerDeliveryRes) {
ACEVSEStatusType.class,
getCommSessionContext().getACEvseController().getACEVSEStatus(EVSENotificationType.NONE));
powerDeliveryRes.setEVSEStatus(jaxbEVSEStatus);
} else if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
} else if (getCommSessionContext().getRequestedEnergyTransferMode() != null && getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
/*
* The MiscUtils method getJAXBElement() cannot be used here because of the difference in the
* class name (DCEVSEStatus) and the name in the XSD (DC_EVSEStatus)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public enum GlobalValues {
*/
V2GTP_HEADER_MAX_PAYLOAD_LENGTH((long) Integer.MAX_VALUE * 2, GlobalTypes.PAYLOAD_LENGTH),

// Protocol versions (1 = IS compliant), see Table 9
// Protocol version of V2GTP messages (1 = IS compliant), see Table 9
V2GTP_VERSION_1_IS(ByteUtils.toByteFromHexString("01"), GlobalTypes.PROTOCOL_VERSION),

// Schema information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@
import org.apache.logging.log4j.Logger;
import com.v2gclarity.risev2g.shared.enumerations.V2GMessages;

/**
* All time restrictions are given as millisecond values.
*
* @author Marc
*
*/
public class TimeRestrictions {

private static Logger logger = LogManager.getLogger(TimeRestrictions.class.getSimpleName());
Expand All @@ -59,15 +53,6 @@ public class TimeRestrictions {
*/
public static final int V2G_EVCC_COMMUNICATION_SETUP_TIMEOUT = 20000;

/**
* Timeout for retrieving a response from the ProtoTCPClient after having sent a request
*/
public static final int PROTO_TCP_CLIENT_RESPONSE_TIMEOUT = 30000;

/**
* Threshold time in seconds for sending the EV controller to sleep
*/
public static final int STAY_AWAKE_THRESHOLD = 125;

public static int getV2gEvccMsgTimeout(V2GMessages messageType) {
switch(messageType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ public static Inet6Address getLinkLocalAddress() {
}


/**
* Is used by the UDP client as well as by the TCP/TLS server whose ports may be in the range
* of 49152 and 65535.
* @return A port number given as an integer value.
*/
public static int getRandomPortNumber() {
return (int) Math.round(Math.random() * (65535-49152)) + 49152;
}


public static byte[] getMacAddress() {
String networkInterfaceConfig = getPropertyValue("network.interface").toString();
NetworkInterface nif = null;
Expand All @@ -114,14 +124,6 @@ public static byte[] getMacAddress() {
return macAddress;
}

/**
* Is used by the UDP client as well as by the TCP/TLS server whose ports may be in the range
* of 49152 and 65535.
* @return A port number given as an integer value.
*/
public static int getRandomPortNumber() {
return (int) Math.round(Math.random() * (65535-49152)) + 49152;
}

/**
* This is a more sophisticated method compared to the getProperty(String propertyName) method
Expand Down Expand Up @@ -246,6 +248,16 @@ public static Object getPropertyValue(String propertyName) {
if (propertyValue.equals("open_exi")) returnValue = "open_exi";
else returnValue = "exificient";
break;
case "voltage.accuracy": // EV property
try {
returnValue = Integer.parseInt(propertyValue);
} catch (NumberFormatException e) {
getLogger().warn("Voltage accuracy '" + propertyValue + "' not supported. " +
"Setting default value to 5.", e);
getV2gEntityConfig().setProperty("voltage.accuracy", "5");
returnValue = 5;
}
break;
default:
getLogger().error("No property with name '" + propertyName + "' found");
}
Expand Down

0 comments on commit cba5e04

Please sign in to comment.