keep charge points for manual configuration
MODIFY
src/server/ocpp/utils/OCPPUtils.ts
src/server/ocpp/utils/OCPPUtils.ts
@@ -986,7 +986,7 @@ export default class OCPPUtils {
return foundTemplate;
}
- public static async enrichChargingStationWithTemplate(tenantID: string, chargingStation: ChargingStation, manualCall?: boolean): Promise<TemplateUpdateResult> {
+ public static async enrichChargingStationWithTemplate(tenantID: string, chargingStation: ChargingStation): Promise<TemplateUpdateResult> {
const templateUpdate: TemplateUpdate = {
chargingStationUpdate: false,
technicalUpdate: false,
@@ -1005,10 +1005,10 @@ export default class OCPPUtils {
// Copy from template
if (chargingStationTemplate) {
// Already updated?
- if (chargingStation.templateHash !== chargingStationTemplate.hash || manualCall) {
+ if (chargingStation.templateHash !== chargingStationTemplate.hash && !chargingStation.manualConfiguration) {
templateUpdate.chargingStationUpdate = true;
// Check Technical Hash
- if (chargingStation.templateHashTechnical !== chargingStationTemplate.hashTechnical && (!chargingStation.manualConfiguration || manualCall)) {
+ if (chargingStation.templateHashTechnical !== chargingStationTemplate.hashTechnical) {
templateUpdate.technicalUpdate = true;
if (Utils.objectHasProperty(chargingStationTemplate.technical, 'maximumPower')) {
chargingStation.maximumPower = chargingStationTemplate.technical.maximumPower;

MODIFY
src/server/rest/v1/service/ChargingStationService.ts
src/server/rest/v1/service/ChargingStationService.ts
@@ -97,7 +97,7 @@ export default class ChargingStationService {
await ocpiClient.removeChargingStation(chargingStation);
}
} catch (error) {
- Logging.logError({
+ await Logging.logError({
tenantID: req.user.tenantID,
module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
action: action,
@@ -117,32 +117,17 @@ export default class ChargingStationService {
chargingStation.forceInactive = filteredRequest.forceInactive;
}
if (Utils.objectHasProperty(filteredRequest, 'manualConfiguration')) {
- if (Utils.getChargingStationCurrentType(chargingStation, null, null) !== CurrentType.DC || !(chargingStation.chargePoints?.length !== 0)) {
// Check manual config
if (!chargingStation.manualConfiguration && filteredRequest.manualConfiguration) {
- for (const connector of chargingStation.connectors) {
- const chargePoint = chargingStation.chargePoints.find((cp) => cp.chargePointID === connector.chargePointID);
- connector.currentType = Utils.getChargingStationCurrentType(chargingStation, chargePoint);
- connector.numberOfConnectedPhase = Utils.getNumberOfConnectedPhases(chargingStation, chargePoint);
- }
- // Do not save charge point
- delete chargingStation.chargePoints;
+ delete chargingStation.templateHash;
+ delete chargingStation.templateHashCapabilities;
+ delete chargingStation.templateHashOcppStandard;
+ delete chargingStation.templateHashOcppVendor;
delete chargingStation.templateHashTechnical;
- rebootRequired = true;
} else if (chargingStation.manualConfiguration && !filteredRequest.manualConfiguration) {
- await OCPPUtils.enrichChargingStationWithTemplate(req.user.tenantID, chargingStation, true);
+ await OCPPUtils.enrichChargingStationWithTemplate(req.user.tenantID, chargingStation);
rebootRequired = true;
}
- } else if (filteredRequest.manualConfiguration) {
- throw new AppError({
- source: Constants.CENTRAL_SERVER,
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Error occurred while updating chargingStation: '${chargingStation.id}'. Manual configuration is only possible for AC Charging Stations`,
- module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
- user: req.user,
- action: action
- });
- }
chargingStation.manualConfiguration = filteredRequest.manualConfiguration;
}
// Existing Connectors
@@ -150,7 +135,7 @@ export default class ChargingStationService {
for (const filteredConnector of filteredRequest.connectors) {
const connector = Utils.getConnectorFromID(chargingStation, filteredConnector.connectorId);
// Update Connectors only if no Charge Point is defined
- if (connector && Utils.isEmptyArray(chargingStation.chargePoints)) {
+ if (connector && (Utils.isEmptyArray(chargingStation.chargePoints) || chargingStation.manualConfiguration)) {
connector.type = filteredConnector.type;
connector.power = filteredConnector.power;
connector.amperage = filteredConnector.amperage;
@@ -161,6 +146,28 @@ export default class ChargingStationService {
connector.phaseAssignmentToGrid = filteredConnector.phaseAssignmentToGrid;
}
}
+ // Existing charge points
+ if (!Utils.isEmptyArray(filteredRequest.chargePoints)) {
+ for (const filteredChargePoint of filteredRequest.chargePoints) {
+ UtilsService.checkIfChargePointValid(chargingStation, filteredChargePoint, req);
+ const chargePoint = Utils.getChargePointFromID(chargingStation, filteredChargePoint.chargePointID);
+ // Update Connectors only if manual configuration is enabled
+ if (chargePoint && chargingStation.manualConfiguration) {
+ chargePoint.chargePointID = filteredChargePoint.chargePointID,
+ chargePoint.currentType = filteredChargePoint.currentType,
+ chargePoint.voltage = filteredChargePoint.voltage,
+ chargePoint.amperage = filteredChargePoint.amperage,
+ chargePoint.numberOfConnectedPhase = filteredChargePoint.numberOfConnectedPhase,
+ chargePoint.cannotChargeInParallel = filteredChargePoint.cannotChargeInParallel,
+ chargePoint.sharePowerToAllConnectors = filteredChargePoint.sharePowerToAllConnectors,
+ chargePoint.excludeFromPowerLimitation = filteredChargePoint.excludeFromPowerLimitation;
+ chargePoint.ocppParamForPowerLimitation = filteredChargePoint.ocppParamForPowerLimitation,
+ chargePoint.power = filteredChargePoint.power,
+ chargePoint.efficiency = filteredChargePoint.efficiency;
+ chargePoint.connectorIDs = filteredChargePoint.connectorIDs;
+ }
+ }
+ }
// Update Site Area
if (siteArea) {
// OCPI Site Area
@@ -209,7 +216,7 @@ export default class ChargingStationService {
// Update
await ChargingStationStorage.saveChargingStation(req.user.tenantID, chargingStation);
// Log
- Logging.logSecurityInfo({
+ await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
source: chargingStation.id, action: action,
user: req.user, module: MODULE_NAME,
@@ -221,12 +228,12 @@ export default class ChargingStationService {
});
if (rebootRequired) {
try {
- await OCPPUtils.triggerChargingStationReset(req.user.tenantID, chargingStation, true);
+ // Await OCPPUtils.triggerChargingStationReset(req.user.tenantID, chargingStation, true);
} catch (error) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
action: action,
- errorCode: HTTPError.CHARGING_STATION_RESET,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
message: 'Error occurred while restarting the charging station',
module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
user: req.user, actionOnUser: req.user,
@@ -347,7 +354,7 @@ export default class ChargingStationService {
});
}
// Log
- Logging.logWarning({
+ await Logging.logWarning({
tenantID: req.user.tenantID,
source: chargingStation.id,
action: action,
@@ -375,7 +382,7 @@ export default class ChargingStationService {
user: req.user
});
}
- Logging.logInfo({
+ await Logging.logInfo({
tenantID: req.user.tenantID,
source: chargingStation.id,
action: action,
@@ -787,7 +794,7 @@ export default class ChargingStationService {
await ChargingStationStorage.deleteChargingStation(req.user.tenantID, chargingStation.id);
}
// Log
- Logging.logSecurityInfo({
+ await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
user: req.user, module: MODULE_NAME, method: 'handleDeleteChargingStation',
message: `Charging Station '${chargingStation.id}' has been deleted successfully`,

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -413,6 +413,89 @@ export default class UtilsService {
}
}
+ public static checkIfChargePointValid(chargingStation: ChargingStation, chargePoint: ChargePoint, req: Request): void {
+ const connectors = Utils.getConnectorsFromChargePoint(chargingStation, chargePoint);
+ let chargePointAmperage = 0;
+ let chargePointPower = 0;
+ for (const connector of connectors) {
+ if (connector.voltage && chargePoint.voltage && connector.voltage !== chargePoint.voltage) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Point does not match the voltage of its connectors',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ if (connector.numberOfConnectedPhase && chargePoint.numberOfConnectedPhase && connector.numberOfConnectedPhase !== chargePoint.numberOfConnectedPhase) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Point does not match the number of phases of its connectors',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ if (connector.currentType && chargePoint.currentType && connector.currentType !== chargePoint.currentType) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Point does not match the currentType of its connectors',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ if (chargePoint.sharePowerToAllConnectors) {
+ if (connector.amperage && chargePoint.amperage && connector.amperage !== chargePoint.amperage) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Points amperage does not equal the amperage of the connectors (shared power between connectors)',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ if (connector.power && chargePoint.power && connector.power !== chargePoint.power) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Points power does not equal the power of the connectors (shared power between connectors)',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ } else {
+ chargePointAmperage += connector.amperage;
+ chargePointPower += connector.power;
+ }
+ }
+ if (chargePointAmperage > 0 && chargePointAmperage !== chargePoint.amperage) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Points power does not match the combined amperage of the connectors (shared power between connectors)',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ if (chargePointPower > 0 && chargePointPower !== chargePoint.power) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.CHARGING_STATION_UPDATE_PARAMS,
+ errorCode: HTTPError.CHARGING_POINT_NOT_VALID,
+ message: 'Charge Points power does not match the combined power of the connectors (shared power between connectors)',
+ module: MODULE_NAME, method: 'checkIfChargePointValid',
+ user: req.user.id
+ });
+ }
+ }
+
public static checkIfSiteValid(site: Partial<Site>, req: Request): void {
if (req.method !== 'POST' && !site.id) {
throw new AppError({

MODIFY
src/server/rest/v1/service/security/ChargingStationSecurity.ts
src/server/rest/v1/service/security/ChargingStationSecurity.ts
@@ -170,6 +170,28 @@ export default class ChargingStationSecurity {
return null;
});
}
+ // Filter charge points
+ if (request.chargePoints) {
+ filteredRequest.chargePoints = request.chargePoints.map((chargePoint) => {
+ if (chargePoint) {
+ return {
+ chargePointID: sanitize(chargePoint.chargePointID),
+ currentType: sanitize(chargePoint.currentType),
+ voltage: sanitize(chargePoint.voltage),
+ amperage: sanitize(chargePoint.amperage),
+ numberOfConnectedPhase: sanitize(chargePoint.numberOfConnectedPhase),
+ cannotChargeInParallel: sanitize(chargePoint.cannotChargeInParallel),
+ sharePowerToAllConnectors: sanitize(chargePoint.sharePowerToAllConnectors),
+ excludeFromPowerLimitation: sanitize(chargePoint.excludeFromPowerLimitation),
+ ocppParamForPowerLimitation: sanitize(chargePoint.ocppParamForPowerLimitation),
+ power: sanitize(chargePoint.power),
+ efficiency: sanitize(chargePoint.efficiency),
+ connectorIDs: chargePoint.connectorIDs.map(sanitize)
+ };
+ }
+ return null;
+ });
+ }
return filteredRequest;
}

MODIFY
src/types/HTTPError.ts
src/types/HTTPError.ts
@@ -66,7 +66,7 @@ export enum HTTPError {
CANNOT_ACQUIRE_LOCK = 510,
INVALID_FILE_FORMAT = 583,
- CHARGING_STATION_RESET = 584,
+ CHARGING_POINT_NOT_VALID = 584,
}
export enum HTTPAuthError {

MODIFY
src/types/requests/HttpChargingStationRequest.ts
src/types/requests/HttpChargingStationRequest.ts
-import { ConnectorType, CurrentType, PhaseAssignmentToGrid } from '../ChargingStation';
+import { ConnectorType, CurrentType, PhaseAssignmentToGrid, Voltage } from '../ChargingStation';
import HttpByIDRequest from './HttpByIDRequest';
import HttpDatabaseRequest from './HttpDatabaseRequest';
@@ -56,8 +56,22 @@ export interface HttpChargingStationParamsUpdateRequest {
manualConfiguration: boolean;
siteAreaID: string;
coordinates: number[];
+ chargePoints: {
+ chargePointID: number;
+ currentType: CurrentType;
+ voltage: Voltage;
+ amperage: number;
+ numberOfConnectedPhase: number;
+ cannotChargeInParallel: boolean;
+ sharePowerToAllConnectors: boolean;
+ excludeFromPowerLimitation: boolean;
+ ocppParamForPowerLimitation: string;
+ power: number;
+ efficiency: number;
+ connectorIDs: number[]}[];
connectors: {
connectorId: number;
+ chargePointID: number;
type: ConnectorType;
power: number;
amperage: number;

keep charge points for manual configuration