Implemented charging points in SAP Smart Charging
MODIFY
src/integration/charging-station-vendor/ChargingStationVendorIntegration.ts
src/integration/charging-station-vendor/ChargingStationVendorIntegration.ts
import { ChargingProfile, ChargingRateUnitType, ChargingSchedule } from '../../types/ChargingProfile';
-import ChargingStation, { ChargePoint, ConnectorCurrentLimit, ConnectorCurrentLimitSource, PowerLimitUnits, StaticLimitAmps } from '../../types/ChargingStation';
+import ChargingStation, { ChargePoint, ConnectorCurrentLimit, ConnectorCurrentLimitSource, StaticLimitAmps } from '../../types/ChargingStation';
import { OCPPChangeConfigurationCommandResult, OCPPChargingProfileStatus, OCPPClearChargingProfileCommandResult, OCPPClearChargingProfileStatus, OCPPConfigurationStatus, OCPPGetCompositeScheduleCommandResult, OCPPGetCompositeScheduleStatus, OCPPSetChargingProfileCommandResult } from '../../types/ocpp/OCPPClient';
import BackendError from '../../exception/BackendError';
@@ -628,7 +628,7 @@ export default abstract class ChargingStationVendorIntegration {
tenantID: tenantID,
source: chargingStation.id,
action: ServerAction.GET_CONNECTOR_CURRENT_LIMIT,
- message: `Get current limitation on Connectors has been called: ${result.limitAmps} A, ${result.limitWatts} W`,
+ message: `Get current limitation on Connectors has been called: ${result.limitAmps} A, ${result.limitWatts}W, source '${result.limitSource}'`,
module: MODULE_NAME, method: 'getCurrentConnectorLimit',
detailedMessages: { result }
});
@@ -642,13 +642,13 @@ export default abstract class ChargingStationVendorIntegration {
// Check connector
if (chargingStation.connectors && vendorSpecificChargingProfile.profile && vendorSpecificChargingProfile.profile.chargingSchedule) {
// Convert to Watts?
- if (chargingStation.powerLimitUnit === PowerLimitUnits.WATT) {
+ if (chargingStation.powerLimitUnit === ChargingRateUnitType.WATT) {
vendorSpecificChargingProfile.profile.chargingSchedule.chargingRateUnit = ChargingRateUnitType.WATT;
}
// Divide the power by the number of connectors and number of phases
for (const schedulePeriod of vendorSpecificChargingProfile.profile.chargingSchedule.chargingSchedulePeriod) {
// Check Unit
- if (chargingStation.powerLimitUnit === PowerLimitUnits.AMPERE) {
+ if (chargingStation.powerLimitUnit === ChargingRateUnitType.AMPERE) {
// Limit Amps per phase
schedulePeriod.limit = this.convertLimitAmpPerPhase(
chargingStation, chargePoint,
@@ -699,7 +699,7 @@ export default abstract class ChargingStationVendorIntegration {
limitAmpPerPhase = this.chargePointToConnectorLimitAmps(chargePoint, limitAmpPerPhase);
}
// Per pahse
- limitAmpPerPhase /= Utils.getChargingStationNumberOfConnectedPhases(chargingStation, chargePoint, connectorID);
+ limitAmpPerPhase /= Utils.getNumberOfConnectedPhases(chargingStation, chargePoint, connectorID);
return limitAmpPerPhase;
}
@@ -711,7 +711,7 @@ export default abstract class ChargingStationVendorIntegration {
limitAmpAllPhases = this.connectorToChargePointLimitAmps(chargePoint, limitAmpAllPhases);
}
// Per pahse
- limitAmpAllPhases *= Utils.getChargingStationNumberOfConnectedPhases(chargingStation, chargePoint, connectorID);
+ limitAmpAllPhases *= Utils.getNumberOfConnectedPhases(chargingStation, chargePoint, connectorID);
return limitAmpAllPhases;
}

MODIFY
src/integration/smart-charging/SmartChargingIntegration.ts
src/integration/smart-charging/SmartChargingIntegration.ts
-import { ActionsResponse } from '../../types/GlobalType';
import BackendError from '../../exception/BackendError';
-import { ChargingProfile } from '../../types/ChargingProfile';
-import Logging from '../../utils/Logging';
import OCPPUtils from '../../server/ocpp/utils/OCPPUtils';
+import { ChargingProfile } from '../../types/ChargingProfile';
+import { ActionsResponse } from '../../types/GlobalType';
import { ServerAction } from '../../types/Server';
-import SiteArea from '../../types/SiteArea';
import { SmartChargingSetting } from '../../types/Setting';
+import SiteArea from '../../types/SiteArea';
+import Constants from '../../utils/Constants';
+import Logging from '../../utils/Logging';
import Utils from '../../utils/Utils';
const MODULE_NAME = 'SmartCharging';
@@ -76,6 +77,42 @@ export default abstract class SmartChargingIntegration<T extends SmartChargingSe
return actionsResponse;
}
+ protected checkIfSiteAreaIsValid(siteArea: SiteArea) {
+ if (!siteArea.maximumPower) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.SMART_CHARGING,
+ module: MODULE_NAME, method: 'checkIfSiteAreaIsValid',
+ message: `Maximum Power is not set in Site Area '${siteArea.name}'`
+ });
+ }
+ if (siteArea.voltage !== 230 && siteArea.voltage !== 110) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.SMART_CHARGING,
+ module: MODULE_NAME, method: 'checkIfSiteAreaIsValid',
+ message: `Voltage must be either 110V or 230V in Site Area '${siteArea.name}'`
+ });
+ }
+ if (siteArea.numberOfPhases !== 1 && siteArea.numberOfPhases !== 3) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.SMART_CHARGING,
+ module: MODULE_NAME, method: 'checkIfSiteAreaIsValid',
+ message: `Number of phases must be either 1 or 3 in Site Area '${siteArea.name}'`
+ });
+ }
+ // Charging Stations
+ if (!siteArea.chargingStations) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.SMART_CHARGING,
+ module: MODULE_NAME, method: 'checkIfSiteAreaIsValid',
+ message: `No Charging Stations found in Site Area '${siteArea.name}'`
+ });
+ }
+ }
+
async abstract buildChargingProfiles(siteArea: SiteArea): Promise<ChargingProfile[]>;
async abstract checkConnection();

MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
import { ChargePointStatus, OCPPAttribute, OCPPAuthorizationStatus, OCPPAuthorizeRequestExtended, OCPPAuthorizeResponse, OCPPBootNotificationRequestExtended, OCPPBootNotificationResponse, OCPPDataTransferRequestExtended, OCPPDataTransferResponse, OCPPDataTransferStatus, OCPPDiagnosticsStatusNotificationRequestExtended, OCPPDiagnosticsStatusNotificationResponse, OCPPFirmwareStatusNotificationRequestExtended, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatRequestExtended, OCPPHeartbeatResponse, OCPPLocation, OCPPMeasurand, OCPPMeterValuesExtended, OCPPMeterValuesResponse, OCPPNormalizedMeterValue, OCPPNormalizedMeterValues, OCPPReadingContext, OCPPSampledValue, OCPPStartTransactionRequestExtended, OCPPStartTransactionResponse, OCPPStatusNotificationRequestExtended, OCPPStatusNotificationResponse, OCPPStopTransactionRequestExtended, OCPPStopTransactionResponse, OCPPUnitOfMeasure, OCPPValueFormat, OCPPVersion, RegistrationStatus } from '../../../types/ocpp/OCPPServer';
-import ChargingStation, { ChargerVendor, Connector, ConnectorCurrentLimitSource, ConnectorType, PowerLimitUnits, SiteAreaLimitSource } from '../../../types/ChargingStation';
+import { ChargingProfilePurposeType, ChargingRateUnitType } from '../../../types/ChargingProfile';
+import ChargingStation, { ChargerVendor, Connector, ConnectorCurrentLimitSource, ConnectorType, SiteAreaLimitSource } from '../../../types/ChargingStation';
import Transaction, { InactivityStatus, TransactionAction } from '../../../types/Transaction';
import Authorizations from '../../../authorization/Authorizations';
import BackendError from '../../../exception/BackendError';
import { BillingDataTransactionStop } from '../../../types/Billing';
import BillingFactory from '../../../integration/billing/BillingFactory';
-import { ChargingProfilePurposeType } from '../../../types/ChargingProfile';
import ChargingStationConfiguration from '../../../types/configuration/ChargingStationConfiguration';
import ChargingStationStorage from '../../../storage/mongodb/ChargingStationStorage';
import ChargingStationVendorFactory from '../../../integration/charging-station-vendor/ChargingStationVendorFactory';
@@ -124,7 +124,7 @@ export default class OCPPService {
// Update props
chargingStation.createdOn = new Date();
chargingStation.issuer = true;
- chargingStation.powerLimitUnit = PowerLimitUnits.AMPERE;
+ chargingStation.powerLimitUnit = ChargingRateUnitType.AMPERE;
// Assign to Site Area
if (token.siteAreaID) {
const siteArea = await SiteAreaStorage.getSiteArea(headers.tenantID, token.siteAreaID);
@@ -365,14 +365,14 @@ export default class OCPPService {
const transaction = await TransactionStorage.getTransaction(headers.tenantID, meterValues.transactionId);
// Save Meter Values
await OCPPStorage.saveMeterValues(headers.tenantID, newMeterValues);
- // Handle Meter Values
+ // Handle Consumptions
await this.buildConsumptionsWithMeterValues(headers.tenantID, transaction, newMeterValues, chargingStation);
- // OCPI
+ // Hndle OCPI
await this.updateOCPITransaction(headers.tenantID, transaction, chargingStation, TransactionAction.UPDATE);
// Save Transaction
await TransactionStorage.saveTransaction(headers.tenantID, transaction);
- // Update Charging Station Consumption
- await this.updateChargingStationConsumption(headers.tenantID, chargingStation, transaction);
+ // Update Charging Station
+ await this.updateChargingStationWithTransaction(headers.tenantID, chargingStation, transaction);
// Save Charging Station
await ChargingStationStorage.saveChargingStation(headers.tenantID, chargingStation);
// Log
@@ -621,8 +621,7 @@ export default class OCPPService {
// Save it
transaction.id = await TransactionStorage.saveTransaction(headers.tenantID, transaction);
// Clean up Charging Station's connector transaction info
- const foundConnector = chargingStation.connectors.find(
- (connector) => connector.connectorId === transaction.connectorId);
+ const foundConnector = Utils.getConnectorFromID(chargingStation, transaction.connectorId);
if (foundConnector) {
foundConnector.currentConsumption = 0;
foundConnector.totalConsumption = 0;
@@ -808,7 +807,7 @@ export default class OCPPService {
});
}
// Check and free the connector
- OCPPUtils.checkAndFreeChargingStationConnector(chargingStation, transaction.connectorId, false);
+ OCPPUtils.checkAndFreeChargingStationConnector(chargingStation, transaction.connectorId);
// Update Heartbeat
chargingStation.lastHeartBeat = new Date();
// Save Charging Station
@@ -897,8 +896,7 @@ export default class OCPPService {
private async updateConnectorStatus(tenantID: string, chargingStation: ChargingStation, statusNotification: OCPPStatusNotificationRequestExtended, bothConnectorsUpdated) {
// Get it
- let foundConnector: Connector = chargingStation.connectors.find(
- (connector) => connector.connectorId === statusNotification.connectorId);
+ let foundConnector: Connector = Utils.getConnectorFromID(chargingStation, statusNotification.connectorId);
if (!foundConnector) {
// Does not exist: Create
foundConnector = {
@@ -1043,7 +1041,7 @@ export default class OCPPService {
await this.stopOrDeleteActiveTransactions(
tenantID, chargingStation.id, statusNotification.connectorId);
// Clean up connector
- OCPPUtils.checkAndFreeChargingStationConnector(chargingStation, statusNotification.connectorId, true);
+ OCPPUtils.checkAndFreeChargingStationConnector(chargingStation, statusNotification.connectorId);
}
}
@@ -1474,10 +1472,9 @@ export default class OCPPService {
}
// Save Consumption
- private async updateChargingStationConsumption(tenantID: string, chargingStation: ChargingStation, transaction: Transaction) {
+ private async updateChargingStationWithTransaction(tenantID: string, chargingStation: ChargingStation, transaction: Transaction) {
// Get the connector
- const foundConnector: Connector = chargingStation.connectors.find(
- (connector) => connector.connectorId === transaction.connectorId);
+ const foundConnector: Connector = Utils.getConnectorFromID(chargingStation, transaction.connectorId);
// Active transaction?
if (!transaction.stop && foundConnector) {
// Set consumption
@@ -1499,7 +1496,7 @@ export default class OCPPService {
Logging.logInfo({
tenantID: tenantID,
source: chargingStation.id,
- module: MODULE_NAME, method: 'updateChargingStationConsumption',
+ module: MODULE_NAME, method: 'updateChargingStationWithTransaction',
action: ServerAction.CONSUMPTION,
user: transaction.userID,
message: `Connector '${foundConnector.connectorId}' > Transaction ID '${foundConnector.activeTransactionID}' > Instant: ${foundConnector.currentConsumption / 1000} kW, Total: ${foundConnector.totalConsumption / 1000} kW.h${foundConnector.currentStateOfCharge ? ', SoC: ' + foundConnector.currentStateOfCharge + ' %' : ''}`

MODIFY
src/server/ocpp/utils/OCPPUtils.ts
src/server/ocpp/utils/OCPPUtils.ts
@@ -731,9 +731,9 @@ export default class OCPPUtils {
return result;
}
- public static checkAndFreeChargingStationConnector(chargingStation: ChargingStation, connectorId: number, saveOtherConnectors = false) {
+ public static checkAndFreeChargingStationConnector(chargingStation: ChargingStation, connectorId: number) {
// Cleanup connector transaction data
- const foundConnector = chargingStation.connectors.find((connector) => connector.connectorId === connectorId);
+ const foundConnector = Utils.getConnectorFromID(chargingStation, connectorId);
if (foundConnector) {
foundConnector.currentConsumption = 0;
foundConnector.totalConsumption = 0;

MODIFY
src/server/ocpp/validation/OCPPValidation.ts
src/server/ocpp/validation/OCPPValidation.ts
@@ -67,8 +67,7 @@ export default class OCPPValidation extends SchemaValidator {
validateStartTransaction(chargingStation: ChargingStation, startTransaction) {
this.validate(this._startTransactionRequest, startTransaction);
// Check Connector ID
- if (!chargingStation.connectors.find(
- (connector) => connector.connectorId === startTransaction.connectorId)) {
+ if (!Utils.getConnectorFromID(chargingStation, startTransaction.connectorId)) {
throw new BackendError({
source: chargingStation.id,
module: MODULE_NAME, method: 'validateStartTransaction',
@@ -106,8 +105,7 @@ export default class OCPPValidation extends SchemaValidator {
meterValues.connectorId = 1;
}
// Check if the transaction ID matches
- const foundConnector = chargingStation.connectors.find(
- (connector) => connector.connectorId === meterValues.connectorId);
+ const foundConnector = Utils.getConnectorFromID(chargingStation, meterValues.connectorId);
if (!foundConnector) {
Logging.logWarning({
tenantID: tenantID,

MODIFY
src/server/rest/service/TransactionService.ts
src/server/rest/service/TransactionService.ts
@@ -948,7 +948,7 @@ export default class TransactionService {
transactionsIDsToDelete.push(transactionId);
} else {
// Check connector
- const foundConnector = transaction.chargeBox.connectors.find((connector) => connector.connectorId === transaction.connectorId);
+ const foundConnector = Utils.getConnectorFromID(transaction.chargeBox, transaction.connectorId);
if (foundConnector && transaction.id === foundConnector.activeTransactionID) {
// Clear connector
OCPPUtils.checkAndFreeChargingStationConnector(transaction.chargeBox, transaction.connectorId);

MODIFY
src/server/rest/service/security/TransactionSecurity.ts
src/server/rest/service/security/TransactionSecurity.ts
@@ -151,7 +151,7 @@ export default class TransactionSecurity {
filteredTransaction.currentSignedData = transaction.currentSignedData;
}
if (!transaction.stop && transaction.chargeBox && transaction.chargeBox.connectors) {
- const foundConnector = transaction.chargeBox.connectors.find((connector) => connector.connectorId === transaction.connectorId);
+ const foundConnector = Utils.getConnectorFromID(transaction.chargeBox, transaction.connectorId);
filteredTransaction.status = foundConnector ? foundConnector.status : null;
}
filteredTransaction.stateOfCharge = transaction.stateOfCharge;

MODIFY
src/storage/mongodb/ChargingStationStorage.ts
src/storage/mongodb/ChargingStationStorage.ts
-import { ChargingProfile, ChargingProfilePurposeType } from '../../types/ChargingProfile';
-import ChargingStation, { ChargingStationOcppParameters, ChargingStationTemplate, Connector, ConnectorType, OcppParameter, PowerLimitUnits } from '../../types/ChargingStation';
-import { ChargingStationInError, ChargingStationInErrorType } from '../../types/InError';
+import fs from 'fs';
+
+import moment from 'moment';
import { GridFSBucket, GridFSBucketReadStream } from 'mongodb';
import BackendError from '../../exception/BackendError';
-import Constants from '../../utils/Constants';
-import Cypher from '../../utils/Cypher';
-import { DataResult } from '../../types/DataResult';
-import DatabaseUtils from './DatabaseUtils';
+import { ChargingProfile, ChargingProfilePurposeType, ChargingRateUnitType } from '../../types/ChargingProfile';
+import ChargingStation, { ChargingStationOcppParameters, ChargingStationTemplate, Connector, ConnectorType, OcppParameter } from '../../types/ChargingStation';
import DbParams from '../../types/database/DbParams';
-import Logging from '../../utils/Logging';
+import { DataResult } from '../../types/DataResult';
+import global from '../../types/GlobalType';
+import { ChargingStationInError, ChargingStationInErrorType } from '../../types/InError';
import { OCPPFirmwareStatus } from '../../types/ocpp/OCPPServer';
import { ServerAction } from '../../types/Server';
import TenantComponents from '../../types/TenantComponents';
-import TenantStorage from './TenantStorage';
+import Constants from '../../utils/Constants';
+import Cypher from '../../utils/Cypher';
+import Logging from '../../utils/Logging';
import Utils from '../../utils/Utils';
-import fs from 'fs';
-import global from '../../types/GlobalType';
-import moment from 'moment';
+import DatabaseUtils from './DatabaseUtils';
+import TenantStorage from './TenantStorage';
const MODULE_NAME = 'ChargingStationStorage';
@@ -921,7 +922,7 @@ export default class ChargingStationStorage {
{ 'chargePointModel': { $exists: false } }, { 'chargePointModel': { $eq: '' } },
{ 'chargePointVendor': { $exists: false } }, { 'chargePointVendor': { $eq: '' } },
{ 'powerLimitUnit': { $exists: false } }, { 'powerLimitUnit': null },
- { 'powerLimitUnit': { $nin: [PowerLimitUnits.AMPERE, PowerLimitUnits.WATT] } },
+ { 'powerLimitUnit': { $nin: [ChargingRateUnitType.AMPERE, ChargingRateUnitType.WATT] } },
{ 'chargingStationURL': { $exists: false } }, { 'chargingStationURL': null }, { 'chargingStationURL': { $eq: '' } },
{ 'connectors.type': { $exists: false } }, { 'connectors.type': null }, { 'connectors.type': { $eq: '' } },
{ 'connectors.type': { $nin: [ConnectorType.CHADEMO, ConnectorType.COMBO_CCS, ConnectorType.DOMESTIC, ConnectorType.TYPE_1, ConnectorType.TYPE_1_CCS, ConnectorType.TYPE_2, ConnectorType.TYPE_3C] } },

MODIFY
src/types/ChargingStation.ts
src/types/ChargingStation.ts
-import { ChargePointStatus, OCPPFirmwareStatus, OCPPProtocol, OCPPVersion } from './ocpp/OCPPServer';
-
+import { ChargingRateUnitType } from './ChargingProfile';
import CreatedUpdatedProps from './CreatedUpdatedProps';
-import { InactivityStatus } from './Transaction';
import { KeyValue } from './GlobalType';
import { OCPIEvse } from './ocpi/OCPIEvse';
+import { ChargePointStatus, OCPPFirmwareStatus, OCPPProtocol, OCPPVersion } from './ocpp/OCPPServer';
import SiteArea from './SiteArea';
+import { InactivityStatus } from './Transaction';
export default interface ChargingStation extends CreatedUpdatedProps {
id?: string;
@@ -38,7 +38,7 @@ export default interface ChargingStation extends CreatedUpdatedProps {
maximumPower: number;
voltage: Voltage;
excludeFromSmartCharging?: boolean;
- powerLimitUnit: PowerLimitUnits;
+ powerLimitUnit: ChargingRateUnitType;
coordinates: number[];
chargePoints: ChargePoint[];
connectors: Connector[];
@@ -81,11 +81,6 @@ export enum Command {
UPDATE_FIRMWARE = 'UpdateFirmware',
}
-export enum PowerLimitUnits {
- WATT = 'W',
- AMPERE = 'A'
-}
-
export enum StaticLimitAmps {
MIN_LIMIT = 6,
}
@@ -179,7 +174,7 @@ export interface ChargingStationTemplate {
technical: {
maximumPower: number;
voltage?: Voltage;
- powerLimitUnit: PowerLimitUnits;
+ powerLimitUnit: ChargingRateUnitType;
chargePoints?: ChargePoint[];
connectors: {
connectorId: number;

MODIFY
src/types/Optimizer.ts
src/types/Optimizer.ts
@@ -11,11 +11,11 @@ export interface OptimizerChargingProfilesResponse {
export interface OptimizerState {
currentTimeSeconds: number;
fuseTree?: OptimizerFuseTree;
- chargingStations?: OptimizerChargingStation[];
+ chargingStations?: OptimizerChargingStationConnectorFuse[];
maximumSiteLimitKW?: number;
cars: OptimizerCar[];
energyPriceHistory?: OptimizerEnergyPriceHistory;
- carAssignments: OptimizerCarAssignment[];
+ carAssignments: OptimizerCarConnectorAssignment[];
}
export interface OptimizerEvent {
@@ -60,9 +60,23 @@ export interface OptimizerEnergyPriceHistory {
date?: string;
}
-export interface OptimizerCarAssignment {
+export interface OptimizerCarConnectorAssignment {
carID: number;
- chargingStationID: number;
+ chargingStationID: number; // It's a connector but for the optimizer this is a Charging Station
+}
+
+export interface OptimizerFuseTreeNode {
+ '@type': 'Fuse' | 'ChargingStation';
+ id?: number;
+ phase1Connected?: boolean;
+ phase2Connected?: boolean;
+ phase3Connected?: boolean;
+ children?: OptimizerFuseTreeNode[];
+}
+
+export interface ConnectorPower {
+ numberOfConnectedPhase: number;
+ totalAmps: number;
}
export interface OptimizerFuse extends OptimizerFuseTreeNode {
@@ -71,20 +85,24 @@ export interface OptimizerFuse extends OptimizerFuseTreeNode {
fusePhase1: number;
fusePhase2: number;
fusePhase3: number;
- children: OptimizerFuseTreeNodeUnion[];
+ children: OptimizerChargingStationFuse[];
}
-export interface OptimizerFuseTreeNode {
- '@type': 'Fuse' | 'ChargingStation';
- children?: OptimizerFuseTreeNodeUnion[];
- id?: number;
- phase1Connected?: boolean;
- phase2Connected?: boolean;
- phase3Connected?: boolean;
+export interface OptimizerChargingStationFuse extends OptimizerFuseTreeNode {
+ '@type': 'Fuse'; // For the optimizer
+ id: number;
+ fusePhase1?: number;
+ fusePhase2?: number;
+ fusePhase3?: number;
+ phaseToGrid?: { [P in OptimizerPhase]?: OptimizerPhase };
+ phaseToChargingStation?: { [P in OptimizerPhase]?: OptimizerPhase };
+ isBEVAllowed?: boolean;
+ isPHEVAllowed?: boolean;
+ status?: OptimizerStationStatus;
}
-export interface OptimizerChargingStation extends OptimizerFuseTreeNode {
- '@type': 'ChargingStation';
+export interface OptimizerChargingStationConnectorFuse extends OptimizerFuseTreeNode {
+ '@type': 'ChargingStation'; // For the optimizer
id: number;
fusePhase1?: number;
fusePhase2?: number;
@@ -108,4 +126,4 @@ export type OptimizerPhase = 'PHASE_1' | 'PHASE_2' | 'PHASE_3';
export type OptimizerStationStatus = 'Free' | 'Charging' | 'Reserved' | 'Blocked' | 'Maintenance' | 'Disconnected';
-export type OptimizerFuseTreeNodeUnion = OptimizerFuse | OptimizerChargingStation;
+export type OptimizerFuseTreeNodeUnion = OptimizerFuse | OptimizerChargingStationConnectorFuse;

MODIFY
src/types/ocpp/OCPPClient.ts
src/types/ocpp/OCPPClient.ts
-import { ChargingProfile, ChargingSchedule, Profile } from '../../types/ChargingProfile';
-
+import { ChargingProfile, ChargingRateUnitType, ChargingSchedule, Profile } from '../../types/ChargingProfile';
import { KeyValue } from '../GlobalType';
-import { PowerLimitUnits } from '../ChargingStation';
export interface OCPPCommandParam {
}
@@ -118,7 +116,7 @@ export enum OCPPChargingProfileStatus {
export interface OCPPGetCompositeScheduleCommandParam extends OCPPCommandParam {
connectorId: number;
duration: number;
- chargingRateUnit?: PowerLimitUnits;
+ chargingRateUnit?: ChargingRateUnitType;
}
export interface OCPPGetCompositeScheduleCommandResult {

MODIFY
src/utils/Utils.ts
src/utils/Utils.ts
-import { ChargePointStatus, OCPPProtocol, OCPPVersion } from '../types/ocpp/OCPPServer';
-import ChargingStation, { ChargePoint, Connector, CurrentType, StaticLimitAmps } from '../types/ChargingStation';
-import User, { UserRole, UserStatus } from '../types/User';
+import fs from 'fs';
+import path from 'path';
+import url from 'url';
+
+import bcrypt from 'bcryptjs';
+import { Request } from 'express';
+import _ from 'lodash';
+import moment from 'moment';
+import { ObjectID } from 'mongodb';
+import passwordGenerator from 'password-generator';
+import tzlookup from 'tz-lookup';
+import { v4 as uuid } from 'uuid';
+import validator from 'validator';
-import { ActionsResponse } from '../types/GlobalType';
-import AppError from '../exception/AppError';
-import Asset from '../types/Asset';
import Authorizations from '../authorization/Authorizations';
+import AppError from '../exception/AppError';
import BackendError from '../exception/BackendError';
+import TenantStorage from '../storage/mongodb/TenantStorage';
+import UserStorage from '../storage/mongodb/UserStorage';
+import Asset from '../types/Asset';
import { Car } from '../types/Car';
import { ChargingProfile } from '../types/ChargingProfile';
+import ChargingStation, { ChargePoint, Connector, CurrentType, StaticLimitAmps } from '../types/ChargingStation';
import Company from '../types/Company';
-import Configuration from './Configuration';
import ConnectorStats from '../types/ConnectorStats';
-import Constants from './Constants';
-import Cypher from './Cypher';
+import { ActionsResponse } from '../types/GlobalType';
import { HTTPError } from '../types/HTTPError';
-import { InactivityStatus } from '../types/Transaction';
-import Logging from './Logging';
import OCPIEndpoint from '../types/ocpi/OCPIEndpoint';
-import { ObjectID } from 'mongodb';
-import { Request } from 'express';
+import { ChargePointStatus, OCPPProtocol, OCPPVersion } from '../types/ocpp/OCPPServer';
import { ServerAction } from '../types/Server';
import { SettingDBContent } from '../types/Setting';
import Site from '../types/Site';
@@ -27,19 +34,13 @@ import SiteArea from '../types/SiteArea';
import Tag from '../types/Tag';
import Tenant from '../types/Tenant';
import TenantComponents from '../types/TenantComponents';
-import TenantStorage from '../storage/mongodb/TenantStorage';
-import UserStorage from '../storage/mongodb/UserStorage';
+import { InactivityStatus } from '../types/Transaction';
+import User, { UserRole, UserStatus } from '../types/User';
import UserToken from '../types/UserToken';
-import _ from 'lodash';
-import bcrypt from 'bcryptjs';
-import fs from 'fs';
-import moment from 'moment';
-import passwordGenerator from 'password-generator';
-import path from 'path';
-import tzlookup from 'tz-lookup';
-import url from 'url';
-import { v4 as uuid } from 'uuid';
-import validator from 'validator';
+import Configuration from './Configuration';
+import Constants from './Constants';
+import Cypher from './Cypher';
+import Logging from './Logging';
const _centralSystemFrontEndConfig = Configuration.getCentralSystemFrontEndConfig();
const _tenants = [];
@@ -566,7 +567,7 @@ export default class Utils {
return 0;
}
- public static getChargingStationNumberOfConnectedPhases(chargingStation: ChargingStation,
+ public static getNumberOfConnectedPhases(chargingStation: ChargingStation,
chargePoint?: ChargePoint, connectorId = 0): number {
if (chargingStation) {
// Check at charge point level
@@ -1246,8 +1247,7 @@ export default class Utils {
user: req.user.id
});
}
- // Smart Charging?
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.SMART_CHARGING) && siteArea.smartCharging) {
+ // Power
if (siteArea.maximumPower <= 0) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
@@ -1258,16 +1258,25 @@ export default class Utils {
user: req.user.id
});
}
- if (siteArea.numberOfPhases !== 1 && siteArea.numberOfPhases !== 3) {
+ if (siteArea.voltage !== 230 && siteArea.voltage !== 110) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
errorCode: HTTPError.GENERAL_ERROR,
- message: `Site area number of phases must be 1 or 3 but got ${siteArea.numberOfPhases}`,
+ message: `Site voltage must be either 110V or 230V but got ${siteArea.voltage} kW`,
module: MODULE_NAME,
method: 'checkIfSiteAreaValid',
user: req.user.id
});
}
+ if (siteArea.numberOfPhases !== 1 && siteArea.numberOfPhases !== 3) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ errorCode: HTTPError.GENERAL_ERROR,
+ message: `Site area number of phases must be either 1 or 3 but got ${siteArea.numberOfPhases}`,
+ module: MODULE_NAME,
+ method: 'checkIfSiteAreaValid',
+ user: req.user.id
+ });
}
}

Implemented charging points in SAP Smart Charging