@citrineos/reporting
Version:
The reporting module for OCPP v2.0.1. This module is not intended to be used directly, but rather as a dependency for other modules.
282 lines • 17 kB
JavaScript
;
// 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.ReportingModule = void 0;
const base_1 = require("@citrineos/base");
const data_1 = require("@citrineos/data");
const util_1 = require("@citrineos/util");
const services_1 = require("./services");
/**
* Component that handles provisioning related messages.
*/
class ReportingModule extends base_1.AbstractModule {
/**
* Constructor
*/
/**
* This is the constructor function that initializes the {@link ReportingModule}.
*
* @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 sub-component logging. If no `logger` is provided, a default {@link Logger<ILogObj>} 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 {ISecurityEventRepository} [securityEventRepository] - An optional parameter of type {@link ISecurityEventRepository} which represents a repository for accessing security event notification data.
*
* @param {IVariableMonitoringRepository} [variableMonitoringRepository] - An optional parameter of type {@link IVariableMonitoringRepository} which represents a repository for accessing and manipulating monitoring data.
*/
constructor(config, cache, sender, handler, logger, deviceModelRepository, securityEventRepository, variableMonitoringRepository) {
super(config, cache, handler || new util_1.RabbitMqReceiver(config, logger), sender || new util_1.RabbitMqSender(config, logger), base_1.EventGroup.Reporting, logger);
/**
* Fields
*/
this._requests = [
base_1.OCPP2_0_1_CallAction.LogStatusNotification,
base_1.OCPP2_0_1_CallAction.NotifyCustomerInformation,
base_1.OCPP2_0_1_CallAction.NotifyReport,
base_1.OCPP2_0_1_CallAction.SecurityEventNotification,
base_1.OCPP2_0_1_CallAction.NotifyMonitoringReport,
];
this._responses = [
base_1.OCPP2_0_1_CallAction.CustomerInformation,
base_1.OCPP2_0_1_CallAction.GetLog,
base_1.OCPP2_0_1_CallAction.GetReport,
base_1.OCPP2_0_1_CallAction.GetBaseReport,
base_1.OCPP2_0_1_CallAction.GetMonitoringReport,
];
this._deviceModelRepository =
deviceModelRepository || new data_1.sequelize.SequelizeDeviceModelRepository(config, this._logger);
this._securityEventRepository =
securityEventRepository ||
new data_1.sequelize.SequelizeSecurityEventRepository(config, this._logger);
this._variableMonitoringRepository =
variableMonitoringRepository ||
new data_1.sequelize.SequelizeVariableMonitoringRepository(config, this._logger);
this._deviceModelService = new services_1.DeviceModelService(this._deviceModelRepository);
}
get deviceModelRepository() {
return this._deviceModelRepository;
}
/**
* Handle Requests
*/
_handleLogStatusNotification(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('LogStatusNotification received:', message, props);
// TODO: LogStatusNotification 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('LogStatusNotification response sent: ', messageConfirmation);
});
}
_handleNotifyCustomerInformation(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('NotifyCustomerInformation request received:', message, props);
// Create response
const response = {};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('NotifyCustomerInformation response sent: ', messageConfirmation);
});
}
_handleNotifyMonitoringReport(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('NotifyMonitoringReport request received:', message, props);
for (const monitorType of message.payload.monitor ? message.payload.monitor : []) {
const stationId = message.context.stationId;
const [component, variable] = yield this._deviceModelRepository.findOrCreateEvseAndComponentAndVariable(monitorType.component, monitorType.variable);
yield this._variableMonitoringRepository.createOrUpdateByMonitoringDataTypeAndStationId(monitorType, component ? component.id : null, variable ? variable.id : null, stationId);
}
// Create response
const response = {};
const messageConfirmation = yield this.sendCallResultWithMessage(message, response);
this._logger.debug('NotifyMonitoringReport response sent: ', messageConfirmation);
});
}
_handleNotifyReport(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.info('NotifyReport received:', message, props);
const timestamp = message.payload.generatedAt;
for (const reportDataType of message.payload.reportData ? message.payload.reportData : []) {
// To keep consistency with VariableAttributeType defined in OCPP 2.0.1:
// mutability: Default is ReadWrite when omitted.
// if it is not present, we set it to ReadWrite
for (const variableAttr of reportDataType.variableAttribute) {
if (!variableAttr.mutability) {
variableAttr.mutability = base_1.OCPP2_0_1.MutabilityEnumType.ReadWrite;
}
}
const variableAttributes = yield this._deviceModelRepository.createOrUpdateDeviceModelByStationId(reportDataType, message.context.stationId, timestamp);
for (const variableAttribute of variableAttributes) {
// Reload is necessary because in createOrUpdateDeviceModelByStationId does not do eager loading
yield variableAttribute.reload({
include: [data_1.Component, data_1.Variable],
});
yield this._deviceModelRepository.updateResultByStationId({
attributeType: variableAttribute.type,
attributeStatus: base_1.OCPP2_0_1.SetVariableStatusEnumType.Accepted,
attributeStatusInfo: { reasonCode: message.action },
component: variableAttribute.component,
variable: variableAttribute.variable,
}, message.context.stationId, timestamp);
}
}
if (!message.payload.tbc) {
// Default if omitted is false
const success = yield this._cache.set(message.payload.requestId.toString(), ReportingModule.GET_BASE_REPORT_COMPLETE_CACHE_VALUE, message.context.stationId);
this._logger.info('Completed', success, message.payload.requestId);
}
else {
// tbc (to be continued) is true
// Continue to set get base report ongoing. Will extend the timeout.
const success = yield this._cache.set(message.payload.requestId.toString(), ReportingModule.GET_BASE_REPORT_ONGOING_CACHE_VALUE, message.context.stationId, this.config.maxCachingSeconds);
this._logger.info('Ongoing', success, message.payload.requestId);
}
// Create response
const response = {};
yield this.sendCallResultWithMessage(message, response);
this._logger.debug('NotifyReport response sent:', message, props);
});
}
_handleSecurityEventNotification(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('SecurityEventNotification request received:', message, props);
yield this._securityEventRepository.createByStationId(message.payload, message.context.stationId);
yield this.sendCallResultWithMessage(message, {});
});
}
/**
* Handle responses
*/
_handleGetBaseReport(message, props) {
this._logger.debug('GetBaseReport response received:', message, props);
}
_handleGetReport(message, props) {
this._logger.debug('GetReport response received:', message, props);
const status = message.payload.status;
const statusInfo = message.payload.statusInfo;
if (status === base_1.OCPP2_0_1.GenericDeviceModelStatusEnumType.Rejected ||
status === base_1.OCPP2_0_1.GenericDeviceModelStatusEnumType.NotSupported) {
this._logger.error('Failed to get report.', status, statusInfo === null || statusInfo === void 0 ? void 0 : statusInfo.reasonCode, statusInfo === null || statusInfo === void 0 ? void 0 : statusInfo.additionalInfo);
}
}
_handleGetMonitoringReport(message, props) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('GetMonitoringReport response received:', message, props);
const status = message.payload.status;
const statusInfo = message.payload.statusInfo;
if (status === base_1.OCPP2_0_1.GenericDeviceModelStatusEnumType.Rejected ||
status === base_1.OCPP2_0_1.GenericDeviceModelStatusEnumType.NotSupported) {
this._logger.error('Failed to get monitoring report.', status, statusInfo === null || statusInfo === void 0 ? void 0 : statusInfo.reasonCode, statusInfo === null || statusInfo === void 0 ? void 0 : statusInfo.additionalInfo);
}
});
}
_handleGetLog(message, props) {
this._logger.debug('GetLog response received:', message, props);
}
_handleCustomerInformation(message, props) {
this._logger.debug('CustomerInformation response received:', message, props);
}
}
exports.ReportingModule = ReportingModule;
/**
* Get Base Report variables. While NotifyReport requests correlated with a GetBaseReport's requestId
* are still being sent, cache value is 'ongoing'. Once a NotifyReport with tbc === false (or undefined)
* is received, cache value is 'complete'.
*/
ReportingModule.GET_BASE_REPORT_REQUEST_ID_MAX = 10000000; // 10,000,000
ReportingModule.GET_BASE_REPORT_ONGOING_CACHE_VALUE = 'ongoing';
ReportingModule.GET_BASE_REPORT_COMPLETE_CACHE_VALUE = 'complete';
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.LogStatusNotification),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleLogStatusNotification", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.NotifyCustomerInformation),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleNotifyCustomerInformation", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.NotifyMonitoringReport),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleNotifyMonitoringReport", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.NotifyReport),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleNotifyReport", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.SecurityEventNotification),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleSecurityEventNotification", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetBaseReport),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ReportingModule.prototype, "_handleGetBaseReport", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetReport),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ReportingModule.prototype, "_handleGetReport", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetMonitoringReport),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ReportingModule.prototype, "_handleGetMonitoringReport", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.GetLog),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ReportingModule.prototype, "_handleGetLog", null);
__decorate([
(0, base_1.AsHandler)(base_1.OCPPVersion.OCPP2_0_1, base_1.OCPP2_0_1_CallAction.CustomerInformation),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ReportingModule.prototype, "_handleCustomerInformation", null);
//# sourceMappingURL=module.js.map