import { BootNotificationResponse, ChangeAvailabilityResponse, ChangeConfigurationResponse, DefaultResponse, GetConfigurationResponse, HeartbeatResponse, RegistrationStatus, SetChargingProfileResponse, StatusNotificationResponse, UnlockConnectorResponse } from '../types/ocpp/1.6/RequestResponses';
import { ChargingProfile, ChargingProfilePurposeType } from '../types/ocpp/1.6/ChargingProfile';
import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration';
-import ChargingStationTemplate, { PowerOutType } from '../types/ChargingStationTemplate';
+import ChargingStationTemplate, { PowerOutType, VoltageOut } from '../types/ChargingStationTemplate';
import Connectors, { Connector } from '../types/Connectors';
import { MeterValue, MeterValueLocation, MeterValueMeasurand, MeterValuePhase, MeterValueUnit, MeterValuesRequest, MeterValuesResponse, SampledValue } from '../types/ocpp/1.6/MeterValues';
import { PerformanceObserver, performance } from 'perf_hooks';
return this.getConnector(id).availability === AvailabilityType.OPERATIVE;
}
+ _isChargingStationAvailable(): boolean {
+ return this.getConnector(0).availability === AvailabilityType.OPERATIVE;
+ }
+
_getTemplateMaxNumberOfConnectors(): number {
return Object.keys(this._stationInfo.Connectors).length;
}
let defaultVoltageOut: number;
switch (this._getPowerOutType()) {
case PowerOutType.AC:
- defaultVoltageOut = 230;
+ defaultVoltageOut = VoltageOut.VOLTAGE_230;
break;
case PowerOutType.DC:
- defaultVoltageOut = 400;
+ defaultVoltageOut = VoltageOut.VOLTAGE_400;
break;
default:
logger.error(errMsg);
}
}, interval);
} else {
- logger.error(`${this._logPrefix()} Charging station MeterValueSampleInterval configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`);
+ logger.error(`${this._logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`);
}
}
this._bootNotificationResponse = await this.sendBootNotification();
if (!this._isRegistered()) {
registrationRetryCount++;
- await Utils.sleep(this._bootNotificationResponse.interval * 1000);
+ await Utils.sleep(this._bootNotificationResponse?.interval ? this._bootNotificationResponse.interval * 1000 : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL);
}
} while (!this._isRegistered() && (registrationRetryCount <= this._getRegistrationMaxRetries() || this._getRegistrationMaxRetries() === -1));
}
}
async onMessage(messageEvent: MessageEvent): Promise<void> {
- let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, '', ''];
- let responseCallback: (payload?, requestPayload?) => void;
+ let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, {}, {}];
+ let responseCallback: (payload?: Record<string, unknown> | string, requestPayload?: Record<string, unknown>) => void;
let rejectCallback: (error: OCPPError) => void;
let requestPayload: Record<string, unknown>;
let errMsg: string;
throw new Error(`Error request for message id ${messageId} is not iterable`);
}
delete this._requests[messageId];
- rejectCallback(new OCPPError(commandName, commandPayload, errorDetails));
+ rejectCallback(new OCPPError(commandName, commandPayload.toString(), errorDetails));
break;
// Error
default:
}
}
- async sendError(messageId: string, err: Error | OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise<unknown> {
- // Check exception type: only OCPP error are accepted
- const error = err instanceof OCPPError ? err : new OCPPError(ErrorType.INTERNAL_ERROR, err.message, err.stack && err.stack);
+ async sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise<unknown> {
// Send error
return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName);
}
- async sendMessage(messageId: string, commandParams, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE, commandName: RequestCommand | IncomingRequestCommand): Promise<any> {
+ async sendMessage(messageId: string, commandParams: any, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE, commandName: RequestCommand | IncomingRequestCommand): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
// Send a message through wsConnection
}
// Yes: Send Message
this._wsConnection.send(messageToSend);
- } else {
+ } else if (commandName !== RequestCommand.BOOT_NOTIFICATION) {
let dups = false;
// Handle dups in buffer
for (const message of this._messageQueue) {
}
// Function that will receive the request's response
- async function responseCallback(payload, requestPayload): Promise<void> {
+ async function responseCallback(payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> {
if (self.getEnableStatistics()) {
self._statistics.addMessage(commandName, messageType);
}
});
}
- async handleResponse(commandName: RequestCommand, payload, requestPayload): Promise<void> {
+ async handleResponse(commandName: RequestCommand, payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> {
const responseCallbackFn = 'handleResponse' + commandName;
if (typeof this[responseCallbackFn] === 'function') {
await this[responseCallbackFn](payload, requestPayload);
return;
}
if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
- await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE);
+ if (!this._isChargingStationAvailable() || !this._isConnectorAvailable(transactionConnectorId)) {
+ await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.UNAVAILABLE);
+ } else {
+ await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE);
+ }
if (this._stationInfo.powerSharedByConnectors) {
this._stationInfo.powerDivider--;
}
logger.debug(this._logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload);
}
- async handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload): Promise<void> {
+ async handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload: Record<string, unknown>): Promise<void> {
let response;
// Call
if (typeof this['handleRequest' + commandName] === 'function') {
return Constants.OCPP_CHARGING_PROFILE_RESPONSE_ACCEPTED;
}
- // FIXME: Handle properly the transaction started case
handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): ChangeAvailabilityResponse {
const connectorId: number = commandPayload.connectorId;
if (!this.getConnector(connectorId)) {
response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
}
this.getConnector(Utils.convertToInt(connector)).availability = commandPayload.type;
- void this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus);
+ response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED && this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus);
}
return response;
} else if (connectorId > 0 && (this.getConnector(0).availability === AvailabilityType.OPERATIVE || (this.getConnector(0).availability === AvailabilityType.INOPERATIVE && commandPayload.type === AvailabilityType.INOPERATIVE))) {
if (this.getConnector(connectorId)?.transactionStarted) {
this.getConnector(connectorId).availability = commandPayload.type;
- void this.sendStatusNotification(connectorId, chargePointStatus);
return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
}
this.getConnector(connectorId).availability = commandPayload.type;
async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise<DefaultResponse> {
const transactionConnectorID: number = commandPayload.connectorId ? commandPayload.connectorId : 1;
- if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) {
- // Check if authorized
- if (this._authorizedTags.find((value) => value === commandPayload.idTag)) {
- await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING);
- // Authorization successful start transaction
- await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag);
- logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
- return Constants.OCPP_RESPONSE_ACCEPTED;
+ if (this._isChargingStationAvailable() && this._isConnectorAvailable(transactionConnectorID)) {
+ if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) {
+ // Check if authorized
+ if (this._authorizedTags.find((value) => value === commandPayload.idTag)) {
+ await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING);
+ // Authorization successful start transaction
+ await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag);
+ logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
+ return Constants.OCPP_RESPONSE_ACCEPTED;
+ }
+ logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
+ return Constants.OCPP_RESPONSE_REJECTED;
}
- logger.error(this._logPrefix() + ' Remote starting transaction REJECTED, idTag ' + commandPayload.idTag);
- return Constants.OCPP_RESPONSE_REJECTED;
+ await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING);
+ // No local authorization check required => start transaction
+ await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag);
+ logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
+ return Constants.OCPP_RESPONSE_ACCEPTED;
}
- await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING);
- // No local authorization check required => start transaction
- await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag);
- logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag);
- return Constants.OCPP_RESPONSE_ACCEPTED;
+ logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag);
+ return Constants.OCPP_RESPONSE_REJECTED;
}
async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise<DefaultResponse> {