@citrineos/configuration
Version:
The configuration module for OCPP v2.0.1. This module is not intended to be used directly, but rather as a dependency for other modules.
701 lines • 42.6 kB
JavaScript
"use strict";
// Copyright (c) 2023 S44, LLC
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigurationModule = void 0;
const base_1 = require("@citrineos/base");
const data_1 = require("@citrineos/data");
const util_1 = require("@citrineos/util");
const uuid_1 = require("uuid");
const DeviceModelService_1 = require("./DeviceModelService");
const BootNotificationService_1 = require("./BootNotificationService");
/**
* Component that handles Configuration related messages.
*/
class ConfigurationModule extends base_1.AbstractModule {
/**
* Constructor
*/
/**
* This is the constructor function that initializes the {@link ConfigurationModule}.
*
* @param {SystemConfig} config - The `config` contains configuration settings for the module.
*
* @param {ICache} [cache] - The cache instance which is shared among the modules & Central System to pass information such as blacklisted actions or boot status.
*
* @param {IMessageSender} [sender] - The `sender` parameter is an optional parameter that represents an instance of the {@link IMessageSender} interface.
* It is used to send messages from the central system to external systems or devices. If no `sender` is provided, a default {@link RabbitMqSender} instance is created and used.
*
* @param {IMessageHandler} [handler] - The `handler` parameter is an optional parameter that represents an instance of the {@link IMessageHandler} interface.
* It is used to handle incoming messages and dispatch them to the appropriate methods or functions. If no `handler` is provided, a default {@link RabbitMqReceiver} instance is created and used.
*
* @param {Logger<ILogObj>} [logger] - The `logger` parameter is an optional parameter that represents an instance of {@link Logger<ILogObj>}.
* It is used to propagate system-wide logger settings and will serve as the parent logger for any subcomponent logging. If no `logger` is provided, a default {@link Logger<ILogObj>} instance is created and used.
*
* @param {IBootRepository} [bootRepository] - An optional parameter of type {@link IBootRepository} which represents a repository for accessing and manipulating authorization data.
* If no `bootRepository` is provided, a default {@link SequelizeBootRepository} instance is created and used.
*
* @param {IDeviceModelRepository} [deviceModelRepository] - An optional parameter of type {@link IDeviceModelRepository} which represents a repository for accessing and manipulating variable data.
* If no `deviceModelRepository` is provided, a default {@link sequelize:deviceModelRepository} instance is created and used.
*
* @param {IMessageInfoRepository} [messageInfoRepository] - An optional parameter of type {@link messageInfoRepository} which
* represents a repository for accessing and manipulating message info data. If no `messageInfoRepository` is provided, a default
* {@link SequelizeMessageInfoRepository} instance is created and used.
*
* @param {ILocationRepository} [locationRepository] - An optional parameter of type {@link locationRepository} which
* represents a repository for accessing and manipulating location data. If no `locationRepository` is provided, a default
* {@link SequelizeLocationRepository} instance is created and used.
*
* @param {IChangeConfigurationRepository} [changeConfigurationRepository] - An optional parameter of type {@link IChangeConfigurationRepository} which
* represents a repository for accessing and manipulating change configuration data. If no `changeConfigurationRepository` is provided, a default
* {@link SequelizeChangeConfigurationRepository} instance is created and used.
*
* @param {IOCPPMessageRepository} [ocppMessageRepository] - An optional parameter of type {@link IOCPPMessageRepository} which
* represents a repository for accessing and manipulating call message data. If no `ocppMessageRepository` is provided, a default
* {@link SequelizeOCPPMessageRepository} instance is created and used.
*
* @param {IdGenerator} [idGenerator] - An optional parameter of type {@link IdGenerator} which
* represents a generator for ids.
*
*If no `deviceModelRepository` is provided, a default {@link sequelize:messageInfoRepository} instance is created and used.
*/
constructor(config, cache, sender, handler, logger, bootRepository, deviceModelRepository, messageInfoRepository, locationRepository, changeConfigurationRepository, ocppMessageRepository, idGenerator) {
super(config, cache, handler || new util_1.RabbitMqReceiver(config, logger), sender || new util_1.RabbitMqSender(config, logger), base_1.EventGroup.Configuration, logger);
this._requests = [
base_1.OCPP2_0_1_CallAction.BootNotification,
base_1.OCPP2_0_1_CallAction.DataTransfer,
base_1.OCPP2_0_1_CallAction.FirmwareStatusNotification,
base_1.OCPP2_0_1_CallAction.Heartbeat,
base_1.OCPP2_0_1_CallAction.NotifyDisplayMessages,
base_1.OCPP2_0_1_CallAction.PublishFirmwareStatusNotification,
base_1.OCPP1_6_CallAction.Heartbeat,
base_1.OCPP1_6_CallAction.BootNotification,
];
this._responses = [
base_1.OCPP2_0_1_CallAction.ChangeAvailability,
base_1.OCPP2_0_1_CallAction.ClearDisplayMessage,
base_1.OCPP2_0_1_CallAction.GetDisplayMessages,
base_1.OCPP2_0_1_CallAction.PublishFirmware,
base_1.OCPP2_0_1_CallAction.Reset,
base_1.OCPP2_0_1_CallAction.SetDisplayMessage,
base_1.OCPP2_0_1_CallAction.SetNetworkProfile,
base_1.OCPP2_0_1_CallAction.TriggerMessage,
base_1.OCPP2_0_1_CallAction.UnpublishFirmware,
base_1.OCPP2_0_1_CallAction.UpdateFirmware,
base_1.OCPP1_6_CallAction.ChangeAvailability,
base_1.OCPP1_6_CallAction.ChangeConfiguration,
base_1.OCPP1_6_CallAction.GetConfiguration,
base_1.OCPP1_6_CallAction.Reset,
base_1.OCPP1_6_CallAction.TriggerMessage,
];
this._bootRepository =
bootRepository || new data_1.sequelize.SequelizeBootRepository(config, this._logger);
this._deviceModelRepository =
deviceModelRepository || new data_1.sequelize.SequelizeDeviceModelRepository(config, this._logger);
this._messageInfoRepository =
messageInfoRepository || new data_1.sequelize.SequelizeMessageInfoRepository(config, this._logger);
this._locationRepository =
locationRepository || new data_1.sequelize.SequelizeLocationRepository(config, this._logger);
this._changeConfigurationRepository =
changeConfigurationRepository ||
new data_1.SequelizeChangeConfigurationRepository(config, this._logger);
this._ocppMessageRepository =
ocppMessageRepository || new data_1.SequelizeOCPPMessageRepository(config, this._logger);
this._deviceModelService = new DeviceModelService_1.DeviceModelService(this._deviceModelRepository);
this._bootService = new BootNotificationService_1.BootNotificationService(this._bootRepository, this._cache, this._config.modules.configuration, this._logger);
this._idGenerator =
idGenerator ||
new util_1.IdGenerator(new data_1.SequelizeChargingStationSequenceRepository(config, this._logger));
}
get bootRepository() {
return this._bootRepository;
}
get deviceModelRepository() {
return this._deviceModelRepository;
}
get messageInfoRepository() {
return this._messageInfoRepository;
}
get locationRepository() {
return this._locationRepository;
}
get changeConfigurationRepository() {
return this._changeConfigurationRepository;
}
get ocppMessageRepository() {
return this._ocppMessageRepository;
}
/**
* Handle OCPP 2.0.1 requests
*/
_handleBootNotification(message, props) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
this._logger.debug('BootNotification received:', message, props);
const stationId = message.context.stationId;
const tenantId = message.context.tenantId;
const timestamp = message.context.timestamp;
const chargingStation = message.payload.chargingStation;
const bootNotificationResponse = yield this._bootService.createBootNotificationResponse(stationId);
// Check cached boot status for charger. Only Pending and Rejected statuses are cached.
const cachedBootStatus = yield this._cache.get(base_1.BOOT_STATUS, stationId);
// Blacklist or whitelist charger actions in cache
yield this._bootService.cacheChargerActionsPermissions(stationId, cachedBootStatus, bootNotificationResponse.status);
const bootNotificationResponseMessageConfirmation = yield this.sendCallResultWithMessage(message, bootNotificationResponse);
// Update or create charging station
yield this._deviceModelService.updateDeviceModel(chargingStation, stationId, timestamp);
if (!bootNotificationResponseMessageConfirmation.success) {
throw new Error('BootNotification failed: ' + bootNotificationResponseMessageConfirmation);
}
if (bootNotificationResponse.status !== base_1.OCPP2_0_1.RegistrationStatusEnumType.Accepted &&
(!cachedBootStatus || bootNotificationResponse.status !== cachedBootStatus)) {
// Cache boot status for charger if (not accepted) and ((not already cached) or (different status from cached status)).
yield this._cache.set(base_1.BOOT_STATUS, bootNotificationResponse.status, stationId);
}
// Update charger-specific boot config with details of most recently sent BootNotificationResponse
const bootConfigDbEntity = yield this._bootService.updateBootConfig(bootNotificationResponse, stationId);
// If boot notification is not pending, do not start configuration.
// If cached boot status is not null and pending, configuration is already in progress - do not start configuration again.
if (bootNotificationResponse.status !== base_1.OCPP2_0_1.RegistrationStatusEnumType.Pending ||
(cachedBootStatus && cachedBootStatus === base_1.OCPP2_0_1.RegistrationStatusEnumType.Pending)) {
return;
}
// GetBaseReport
// TODO Consider refactoring GetBaseReport and SetVariables sections as methods to be used by their respective message api endpoints as well
if ((_a = bootConfigDbEntity.getBaseReportOnPending) !== null && _a !== void 0 ? _a : (_b = this._config.modules.configuration.ocpp2_0_1) === null || _b === void 0 ? void 0 : _b.getBaseReportOnPending) {
// Remove Notify Report from blacklist
yield this._cache.remove(base_1.OCPP2_0_1_CallAction.NotifyReport, stationId);
const getBaseReportRequest = yield this._bootService.createGetBaseReportRequest(stationId, this._config.maxCachingSeconds);
const getBaseReportConfirmation = yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetBaseReport, getBaseReportRequest);
yield this._bootService.confirmGetBaseReportSuccess(stationId, getBaseReportRequest.requestId.toString(), getBaseReportConfirmation, this._config.maxCachingSeconds);
// Make sure GetBaseReport doesn't re-trigger on next boot attempt
bootConfigDbEntity.getBaseReportOnPending = false;
yield bootConfigDbEntity.save();
}
// SetVariables
let rejectedSetVariable = false;
let rebootSetVariable = false;
if (bootConfigDbEntity.pendingBootSetVariables &&
bootConfigDbEntity.pendingBootSetVariables.length > 0) {
bootConfigDbEntity.variablesRejectedOnLastBoot = [];
let setVariableData = yield this._deviceModelRepository.readAllSetVariableByStationId(stationId);
// If ItemsPerMessageSetVariables not set, send all variables at once
const itemsPerMessageSetVariables = (_c = (yield this._deviceModelService.getItemsPerMessageSetVariablesByStationId(stationId))) !== null && _c !== void 0 ? _c : setVariableData.length;
while (setVariableData.length > 0) {
const correlationId = (0, uuid_1.v4)();
const cacheCallbackPromise = this._cache.onChange(correlationId, this._config.maxCachingSeconds, stationId); // x2 fudge factor for any network lag
yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.SetVariables, {
setVariableData: setVariableData.slice(0, itemsPerMessageSetVariables),
}, undefined, correlationId);
setVariableData = setVariableData.slice(itemsPerMessageSetVariables);
const setVariablesResponseJsonString = yield cacheCallbackPromise;
if (setVariablesResponseJsonString) {
if (rejectedSetVariable && rebootSetVariable) {
continue;
}
const setVariablesResponse = JSON.parse(setVariablesResponseJsonString);
setVariablesResponse.setVariableResult.forEach((result) => {
if (result.attributeStatus === base_1.OCPP2_0_1.SetVariableStatusEnumType.Rejected) {
rejectedSetVariable = true;
}
else if (result.attributeStatus === base_1.OCPP2_0_1.SetVariableStatusEnumType.RebootRequired) {
rebootSetVariable = true;
}
});
}
else {
throw new Error('SetVariables response not found');
}
}
const doNotBootWithRejectedVariables = !((_d = bootConfigDbEntity.bootWithRejectedVariables) !== null && _d !== void 0 ? _d : (_e = this._config.modules.configuration.ocpp2_0_1) === null || _e === void 0 ? void 0 : _e.bootWithRejectedVariables);
if (rejectedSetVariable && doNotBootWithRejectedVariables) {
bootConfigDbEntity.status = base_1.OCPP2_0_1.RegistrationStatusEnumType.Rejected;
yield bootConfigDbEntity.save();
// No more to do.
return;
}
}
if ((_f = this._config.modules.configuration.ocpp2_0_1) === null || _f === void 0 ? void 0 : _f.autoAccept) {
// Update boot config with status accepted
// TODO: Determine how/if StatusInfo should be generated
bootConfigDbEntity.status = base_1.OCPP2_0_1.RegistrationStatusEnumType.Accepted;
yield bootConfigDbEntity.save();
}
if (rebootSetVariable) {
// Charger SHALL not be in a transaction as it has not yet successfully booted, therefore it is appropriate to send an Immediate Reset
yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.Reset, {
type: base_1.OCPP2_0_1.ResetEnumType.Immediate,
});
}
else {
// We could trigger the new boot immediately rather than wait for the retry, as nothing more now needs to be done.
// However, B02.FR.02 - Spec allows for TriggerMessageRequest - OCTT fails over trigger
// Commenting out until OCTT behavior changes.
// this.sendCall(stationId, tenantId, OCPPVersion.OCPP2_0_1, OCPP2_0_1_CallAction.TriggerMessage,
// { requestedMessage: MessageTriggerEnumType.BootNotification } as TriggerMessageRequest);
}
});
}
_handleHeartbeat(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('Heartbeat received:', message, props);
// Create response
const response = {
currentTime: new Date().toISOString(),
};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('Heartbeat response sent: ', messageConfirmation);
});
}
_handleNotifyDisplayMessages(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('NotifyDisplayMessages received: ', message, props);
const messageInfoTypes = message.payload.messageInfo;
for (const messageInfoType of messageInfoTypes) {
let componentId;
if (messageInfoType.display) {
const component = yield this._deviceModelRepository.findOrCreateEvseAndComponent(messageInfoType.display, message.context.tenantId);
componentId = component.id;
}
yield this._messageInfoRepository.createOrUpdateByMessageInfoTypeAndStationId(messageInfoType, message.context.stationId, componentId);
}
// Create response
const response = {};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('NotifyDisplayMessages response sent: ', messageConfirmation);
});
}
_handleFirmwareStatusNotification(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('FirmwareStatusNotification received:', message, props);
// TODO: FirmwareStatusNotification is usually triggered. Ideally, it should be sent to the callbackUrl from the message api that sent the trigger message
// Create response
const response = {};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('FirmwareStatusNotification response sent: ', messageConfirmation);
});
}
_handleDataTransfer(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('DataTransfer received:', message, props);
// Create response
const response = {
status: base_1.OCPP2_0_1.DataTransferStatusEnumType.Rejected,
statusInfo: { reasonCode: base_1.ErrorCode.NotImplemented },
};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('DataTransfer response sent: ', messageConfirmation);
});
}
/**
* Handle OCPP 2.0.1 responses
*/
_handleChangeAvailability(message, props) {
this._logger.debug('ChangeAvailability response received:', message, props);
}
_handleSetNetworkProfile(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('SetNetworkProfile response received:', message, props);
if (message.payload.status == base_1.OCPP2_0_1.SetNetworkProfileStatusEnumType.Accepted) {
const setNetworkProfile = yield data_1.SetNetworkProfile.findOne({
where: { correlationId: message.context.correlationId },
});
if (setNetworkProfile) {
const serverNetworkProfile = yield data_1.ServerNetworkProfile.findByPk(setNetworkProfile.websocketServerConfigId);
if (serverNetworkProfile) {
const chargingStation = yield data_1.ChargingStation.findByPk(message.context.stationId);
if (chargingStation) {
const [chargingStationNetworkProfile] = yield data_1.ChargingStationNetworkProfile.findOrBuild({
where: {
stationId: chargingStation.id,
configurationSlot: setNetworkProfile.configurationSlot,
},
});
chargingStationNetworkProfile.websocketServerConfigId =
setNetworkProfile.websocketServerConfigId;
chargingStationNetworkProfile.setNetworkProfileId = setNetworkProfile.id;
yield chargingStationNetworkProfile.save();
}
}
}
}
});
}
_handleGetDisplayMessages(message, props) {
this._logger.debug('GetDisplayMessages response received:', message, props);
}
_handleSetDisplayMessage(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('SetDisplayMessage response received:', message, props);
const status = message.payload.status;
// when charger station accepts the set message info request
// we trigger a get all display messages request to update stored message info in db
if (status === base_1.OCPP2_0_1.DisplayMessageStatusEnumType.Accepted) {
yield this._messageInfoRepository.deactivateAllByStationId(message.context.stationId);
yield this.sendCall(message.context.stationId, message.context.tenantId, base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetDisplayMessages, {
requestId: yield this._idGenerator.generateRequestId(message.context.stationId, base_1.ChargingStationSequenceType.getDisplayMessages),
});
}
});
}
_handlePublishFirmware(message, props) {
this._logger.debug('PublishFirmware response received:', message, props);
}
_handleUnpublishFirmware(message, props) {
this._logger.debug('UnpublishFirmware response received:', message, props);
}
_handleUpdateFirmware(message, props) {
this._logger.debug('UpdateFirmware response received:', message, props);
}
_handleReset(message, props) {
this._logger.debug('Reset response received:', message, props);
}
_handleTriggerMessage(message, props) {
this._logger.debug('TriggerMessage response received:', message, props);
}
_handleClearDisplayMessage(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('ClearDisplayMessage response received:', message, props);
const status = message.payload.status;
// when charger station accepts the clear message info request
// we trigger a get all display messages request to update stored message info in db
if (status === base_1.OCPP2_0_1.ClearMessageStatusEnumType.Accepted) {
yield this._messageInfoRepository.deactivateAllByStationId(message.context.stationId);
yield this.sendCall(message.context.stationId, message.context.tenantId, base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetDisplayMessages, {
requestId: yield this._idGenerator.generateRequestId(message.context.stationId, base_1.ChargingStationSequenceType.getDisplayMessages),
});
}
});
}
/**
* Handle OCPP 1.6 requests
*/
_handle16Heartbeat(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('Heartbeat received:', message, props);
const response = {
currentTime: new Date().toISOString(),
};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('Heartbeat response sent: ', messageConfirmation);
});
}
_handleOcpp16BootNotification(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('OCPP 1.6 BootNotification request received:', message, props);
const stationId = message.context.stationId;
const tenantId = message.context.tenantId;
const request = message.payload;
// 1. Send BootNotification response
// Create BootNotification response
const bootNotificationResponse = yield this._bootService.createOcpp16BootNotificationResponse(stationId);
// Check cached boot status for charger. Only Pending and Rejected statuses are cached.
const cachedBootStatus = yield this._cache.get(base_1.BOOT_STATUS, stationId);
// Blacklist or whitelist charger actions
yield this._bootService.cacheOcpp16ChargerActionsPermissions(stationId, cachedBootStatus, bootNotificationResponse.status);
// Send BootNotification response
const bootNotificationResponseMessageConfirmation = yield this.sendCallResultWithMessage(message, bootNotificationResponse);
// Create or update charging station
this._logger.debug(`Creating or updating charging station: ${stationId}`);
yield this._locationRepository.createOrUpdateChargingStation(data_1.ChargingStation.build({
id: stationId,
chargePointVendor: request.chargePointVendor,
chargePointModel: request.chargePointModel,
chargePointSerialNumber: request.chargePointSerialNumber,
chargeBoxSerialNumber: request.chargeBoxSerialNumber,
firmwareVersion: request.firmwareVersion,
iccid: request.iccid,
imsi: request.imsi,
meterType: request.meterType,
meterSerialNumber: request.meterSerialNumber,
}));
// Check if response was successful
if (!bootNotificationResponseMessageConfirmation.success) {
throw new Error('Send BootNotification response failed: ' + bootNotificationResponseMessageConfirmation);
}
// 2. Update boot status in cache and db entity
// Cache boot status for charger if (not accepted) and ((not already cached) or (different status from cached status)).
if (bootNotificationResponse.status !== base_1.OCPP1_6.BootNotificationResponseStatus.Accepted &&
(!cachedBootStatus || bootNotificationResponse.status !== cachedBootStatus)) {
yield this._cache.set(base_1.BOOT_STATUS, bootNotificationResponse.status, stationId);
}
// Update boot with details of most recently sent BootNotificationResponse
const bootEntity = yield this._bootService.updateOcpp16BootConfig(bootNotificationResponse, stationId);
// 3. Sync configurations
// If boot notification is not pending, do not start configuration.
// If cached boot status is not null and pending, configuration is already in progress - do not start configuration again.
if (bootNotificationResponse.status !== base_1.OCPP1_6.BootNotificationResponseStatus.Pending ||
(cachedBootStatus && cachedBootStatus === base_1.OCPP1_6.BootNotificationResponseStatus.Pending)) {
return;
}
let changeConfigurationsOnPending = false;
let getConfigurationsOnPending = true;
// Change Configurations on charging station
const configurations = yield this._changeConfigurationRepository.readAllByQuery({
where: {
stationId,
},
});
// Remove ChangeConfiguration call action from blacklist
yield this._cache.remove(base_1.OCPP1_6_CallAction.ChangeConfiguration, stationId);
// Set each configuration on Charging Station
for (const config of configurations) {
const correlationId = (0, uuid_1.v4)();
const cacheCallbackPromise = this._cache.onChange(correlationId, this._config.maxCachingSeconds, stationId);
const changeConfigurationResponseMessageConfirmation = yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.ChangeConfiguration, {
key: config.key,
value: config.value,
}, undefined, correlationId);
if (!changeConfigurationResponseMessageConfirmation.success) {
changeConfigurationsOnPending = true;
}
// wait before sending next call
yield cacheCallbackPromise;
}
// Get Configurations from charging station
// Remove GetConfiguration call action from blacklist
yield this._cache.remove(base_1.OCPP1_6_CallAction.GetConfiguration, stationId);
// Send GetConfiguration request to charger
const getConfigurationResponseMessageConfirmation = yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.GetConfiguration, {});
if (getConfigurationResponseMessageConfirmation.success) {
getConfigurationsOnPending = false;
}
// Update configuration related fields on boot entity
yield this._bootRepository.updateByKey({
changeConfigurationsOnPending,
getConfigurationsOnPending,
}, bootEntity.id);
// 4. Trigger another boot when pending
yield this._cache.remove(base_1.OCPP1_6_CallAction.TriggerMessage, stationId);
yield this.sendCall(stationId, tenantId, base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.TriggerMessage, {
requestedMessage: base_1.OCPP1_6.TriggerMessageRequestRequestedMessage.BootNotification,
});
});
}
/**
* Handle OCPP 1.6 response
*/
_handleOcpp16GetConfiguration(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('OCPP 1.6 GetConfiguration response received:', message, props);
const stationId = message.context.stationId;
const configurations = message.payload.configurationKey;
if (configurations && configurations.length > 0) {
for (const config of configurations) {
if (config.key) {
yield this._changeConfigurationRepository.createOrUpdateChangeConfiguration({
stationId,
key: config.key,
value: config.value,
readonly: config.readonly,
});
}
}
}
});
}
_handleOcpp16ChangeConfiguration(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('OCPP 1.6 ChangeConfiguration response received:', message, props);
const stationId = message.context.stationId;
const correlationId = message.context.correlationId;
const request = yield this._ocppMessageRepository.readOnlyOneByQuery({
where: {
stationId,
correlationId,
origin: base_1.MessageOrigin.ChargingStationManagementSystem,
},
});
if (!request) {
this._logger.error(`No valid ChangeConfigurationRequest found for correlationId ${correlationId}`);
}
const status = message.payload.status;
const key = request === null || request === void 0 ? void 0 : request.message[3].key;
const value = request === null || request === void 0 ? void 0 : request.message[3].value;
if (status == base_1.OCPP1_6.ChangeConfigurationResponseStatus.Rejected ||
status == base_1.OCPP1_6.ChangeConfigurationResponseStatus.NotSupported) {
this._logger.warn(`Attempted ChangeConfiguration ${correlationId} for ${key}:${value} unsuccessful with status ${status}`);
return;
}
else {
const config = yield this._changeConfigurationRepository.createOrUpdateChangeConfiguration({
stationId,
key,
value,
});
if (!config) {
this._logger.error(`Failed to create or update configuration ${key}:${value} on ${stationId}`);
}
else {
this._logger.debug(`Updated changeConfiguration ${key}:${value}`);
}
}
});
}
_handleOcpp16TriggerMessage(message, props) {
this._logger.debug('TriggerMessage response received:', message, props);
if (message.payload.status !== base_1.OCPP1_6.TriggerMessageResponseStatus.Accepted) {
this._logger.error('TriggerMessage failed with status:', message);
}
}
_handle16Reset(message, props) {
this._logger.debug('Reset response received:', message, props);
}
_handleOcpp16ChangeAvailability(message, props) {
this._logger.debug('ChangeAvailability response received:', message, props);
}
}
exports.ConfigurationModule = ConfigurationModule;
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.BootNotification),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleBootNotification", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.Heartbeat),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleHeartbeat", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.NotifyDisplayMessages),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleNotifyDisplayMessages", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.FirmwareStatusNotification),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleFirmwareStatusNotification", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.DataTransfer),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleDataTransfer", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.ChangeAvailability),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleChangeAvailability", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.SetNetworkProfile),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleSetNetworkProfile", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetDisplayMessages),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleGetDisplayMessages", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.SetDisplayMessage),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleSetDisplayMessage", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.PublishFirmware),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handlePublishFirmware", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.UnpublishFirmware),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleUnpublishFirmware", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.UpdateFirmware),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleUpdateFirmware", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.Reset),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleReset", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.TriggerMessage),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleTriggerMessage", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.ClearDisplayMessage),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleClearDisplayMessage", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.Heartbeat),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handle16Heartbeat", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.BootNotification),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleOcpp16BootNotification", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.GetConfiguration),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleOcpp16GetConfiguration", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.ChangeConfiguration),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ConfigurationModule.prototype, "_handleOcpp16ChangeConfiguration", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.TriggerMessage),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleOcpp16TriggerMessage", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.Reset),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handle16Reset", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP1_6, base_1.OCPP1_6_CallAction.ChangeAvailability),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ConfigurationModule.prototype, "_handleOcpp16ChangeAvailability", null);
//# sourceMappingURL=module.js.map