Implement EV-Ready 13A per phase minimum
MODIFY
src/integration/charging-station-vendor/ChargingStationVendorIntegration.ts
src/integration/charging-station-vendor/ChargingStationVendorIntegration.ts
@@ -27,6 +27,8 @@ export default abstract class ChargingStationVendorIntegration {
public async setStaticPowerLimitation(tenantID: string, chargingStation: ChargingStation,
chargePoint?: ChargePoint, maxAmps?: number): Promise<OCPPChangeConfigurationCommandResult> {
+ const numberOfPhases = Utils.getNumberOfConnectedPhases(chargingStation, chargePoint, 0);
+ const numberOfConnectors = chargePoint ? chargePoint.connectorIDs.length : chargingStation.connectors.length;
if (chargePoint.excludeFromPowerLimitation) {
Logging.logWarning({
tenantID: tenantID,
@@ -58,12 +60,12 @@ export default abstract class ChargingStationVendorIntegration {
message: 'Charging Station capabilities or configuration does not support static power limitation'
});
}
- if (maxAmps < StaticLimitAmps.MIN_LIMIT) {
+ if (maxAmps < (StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * numberOfConnectors)) {
throw new BackendError({
source: chargingStation.id,
action: ServerAction.CHARGING_STATION_LIMIT_POWER,
module: MODULE_NAME, method: 'setStaticPowerLimitation',
- message: `Cannot set the minimum power limit to ${maxAmps}A, minimum expected ${StaticLimitAmps.MIN_LIMIT}A`,
+ message: `Cannot set the minimum power limit to ${maxAmps}A, minimum expected ${StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * numberOfConnectors}A`,
});
}
if (Utils.isEmptyArray(chargingStation.connectors)) {

MODIFY
src/server/rest/service/ChargingStationService.ts
src/server/rest/service/ChargingStationService.ts
@@ -147,16 +147,6 @@ export default class ChargingStationService {
// Filter
const filteredRequest = ChargingStationSecurity.filterChargingStationLimitPowerRequest(req.body);
// Check
- if (filteredRequest.ampLimitValue < StaticLimitAmps.MIN_LIMIT) {
- throw new AppError({
- source: filteredRequest.chargeBoxID,
- action: action,
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Limitation to ${filteredRequest.ampLimitValue}A is too low, min required is ${StaticLimitAmps.MIN_LIMIT}A`,
- module: MODULE_NAME, method: 'handleChargingStationLimitPower',
- user: req.user
- });
- }
if (!filteredRequest.chargePointID) {
throw new AppError({
source: filteredRequest.chargeBoxID,
@@ -167,13 +157,26 @@ export default class ChargingStationService {
user: req.user
});
}
- // Check
+ // Charging Station
const chargingStation = await ChargingStationStorage.getChargingStation(req.user.tenantID, filteredRequest.chargeBoxID);
UtilsService.assertObjectExists(action, chargingStation, `Charging Station '${filteredRequest.chargeBoxID}' does not exist.`,
MODULE_NAME, 'handleChargingStationLimitPower', req.user);
+ // Charge Point
const chargePoint = Utils.getChargePointFromID(chargingStation, filteredRequest.chargePointID);
UtilsService.assertObjectExists(action, chargePoint, `Charge Point '${filteredRequest.chargePointID}' does not exist.`,
MODULE_NAME, 'handleChargingStationLimitPower', req.user);
+ // Min Current
+ const numberOfPhases = Utils.getNumberOfConnectedPhases(chargingStation, chargePoint, 0);
+ if (filteredRequest.ampLimitValue < (StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * chargePoint.connectorIDs.length)) {
+ throw new AppError({
+ source: filteredRequest.chargeBoxID,
+ action: action,
+ errorCode: HTTPError.GENERAL_ERROR,
+ message: `Limitation to ${filteredRequest.ampLimitValue}A is too low, min required is ${StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * chargePoint.connectorIDs.length}A`,
+ module: MODULE_NAME, method: 'handleChargingStationLimitPower',
+ user: req.user
+ });
+ }
let siteID = null;
if (Utils.isComponentActiveFromToken(req.user, TenantComponents.ORGANIZATION)) {
// Get the Site Area
@@ -204,7 +207,7 @@ export default class ChargingStationService {
});
}
// Check if static limitation is supported
- if (chargingStationVendor.hasStaticLimitationSupport(chargingStation)) {
+ if (!chargingStationVendor.hasStaticLimitationSupport(chargingStation)) {
throw new AppError({
source: chargingStation.id,
action: action,

MODIFY
src/types/ChargingStation.ts
src/types/ChargingStation.ts
@@ -85,7 +85,7 @@ export enum Command {
}
export enum StaticLimitAmps {
- MIN_LIMIT = 6,
+ MIN_LIMIT_PER_PHASE = 13,
}
export interface Connector {

MODIFY
src/utils/Utils.ts
src/utils/Utils.ts
@@ -534,14 +534,14 @@ export default class Utils {
if (!chargingStation.chargePoints) {
return null;
}
- return chargingStation.chargePoints.find((chargePoint) => chargePoint.chargePointID === chargePointID);
+ return chargingStation.chargePoints.find((chargePoint) => chargePoint && (chargePoint.chargePointID === chargePointID));
}
public static getConnectorFromID(chargingStation: ChargingStation, connectorID: number): Connector {
if (!chargingStation.connectors) {
return null;
}
- return chargingStation.connectors.find((connector) => connector.connectorId === connectorID);
+ return chargingStation.connectors.find((connector) => connector && (connector.connectorId === connectorID));
}
public static computeChargingStationTotalAmps(chargingStation: ChargingStation): number {
@@ -1190,6 +1190,26 @@ export default class Utils {
public static checkIfChargingProfileIsValid(chargingStation: ChargingStation, chargePoint: ChargePoint,
filteredRequest: ChargingProfile, req: Request): void {
+ if (!Utils.objectHasProperty(filteredRequest, 'chargingStationID')) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_PROFILE_UPDATE,
+ errorCode: HTTPError.GENERAL_ERROR,
+ message: 'Charging Station ID is mandatory',
+ module: MODULE_NAME, method: 'checkIfChargingProfileIsValid',
+ user: req.user.id
+ });
+ }
+ if (!Utils.objectHasProperty(filteredRequest, 'connectorID')) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_PROFILE_UPDATE,
+ errorCode: HTTPError.GENERAL_ERROR,
+ message: 'Connector ID is mandatory',
+ module: MODULE_NAME, method: 'checkIfChargingProfileIsValid',
+ user: req.user.id
+ });
+ }
if (!filteredRequest.profile) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
@@ -1246,16 +1266,19 @@ export default class Utils {
});
}
// Check Max Limitation of each Schedule
+ const numberOfPhases = Utils.getNumberOfConnectedPhases(chargingStation, null, filteredRequest.connectorID);
+ const numberOfConnectors = filteredRequest.connectorID === 0 ?
+ (chargePoint ? chargePoint.connectorIDs.length : chargingStation.connectors.length) : 1;
const maxAmpLimit = Utils.getChargingStationAmperageLimit(
chargingStation, chargePoint, filteredRequest.connectorID);
for (const chargingSchedulePeriod of filteredRequest.profile.chargingSchedule.chargingSchedulePeriod) {
// Check Min
- if (chargingSchedulePeriod.limit < StaticLimitAmps.MIN_LIMIT) {
+ if (chargingSchedulePeriod.limit < (StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * numberOfConnectors)) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
action: ServerAction.CHARGING_PROFILE_UPDATE,
errorCode: HTTPError.GENERAL_ERROR,
- message: `Charging Schedule is below the min limitation (${StaticLimitAmps.MIN_LIMIT}A)`,
+ message: `Charging Schedule is below the min limitation (${(StaticLimitAmps.MIN_LIMIT_PER_PHASE * numberOfPhases * numberOfConnectors)}A)`,
module: MODULE_NAME, method: 'checkIfChargingProfileIsValid',
user: req.user.id,
detailedMessages: { chargingSchedulePeriod }

Implement EV-Ready 13A per phase minimum