moved hashes outside template level in charging station template type
+ aligned code
MODIFY
src/assets/schemas/chargingstation/chargingstation-template-save.json
src/assets/schemas/chargingstation/chargingstation-template-save.json
"$ref": "common#/definitions/lastChangedOn"
},
"template": {
- "type": "object",
- "properties": {
- "chargePointVendor": {
- "type": "string"
- },
- "extraFilters": {
- "type": "object",
- "properties": {
- "chargePointModel": {
- "type": "string"
- },
- "chargeBoxSerialNumber": {
- "type": "string"
- }
- },
- "additionalProperties": false
+ "$ref": "chargingstation-template#/definitions/template"
},
"hash": {
"type": "string"
},
"hashOcppVendor": {
"type": "string"
- },
- "technical": {
- "type": "object",
- "properties": {
- "masterSlave": {
- "type": "boolean"
- },
- "maximumPower": {
- "type": "integer"
- },
- "voltage": {
- "type": "integer",
- "enum": [
- 110,
- 230
- ]
- },
- "powerLimitUnit": {
- "type": "string"
- },
- "excludeFromPowerLimitation": {
- "type": "boolean"
- },
- "chargePoints": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "chargePointID": {
- "type": "integer"
- },
- "currentType": {
- "type": "string",
- "enum": ["AC", "DC"]
- },
- "amperage": {
- "type": "integer"
- },
- "efficiency": {
- "type": "integer"
- },
- "numberOfConnectedPhase": {
- "type": "integer",
- "enum": [1, 3]
- },
- "cannotChargeInParallel": {
- "type": "boolean"
- },
- "sharePowerToAllConnectors": {
- "type": "boolean"
- },
- "excludeFromPowerLimitation": {
- "type": "boolean"
- },
- "ocppParamForPowerLimitation": {
- "type": "string"
- },
- "power": {
- "type": "integer"
- },
- "connectorIDs": {
- "type": "array",
- "items": {
- "type": "integer"
- }
- }
- },
- "additionalProperties": false,
- "required": [
- "chargePointID",
- "currentType",
- "amperage",
- "numberOfConnectedPhase",
- "cannotChargeInParallel",
- "sharePowerToAllConnectors",
- "ocppParamForPowerLimitation",
- "power",
- "connectorIDs"
- ]
- }
- },
- "connectors": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "connectorId": {
- "type": "integer"
- },
- "type": {
- "type": "string",
- "enum": ["T1", "T2", "CCS", "C", "D"]
- },
- "power": {
- "type": "integer"
- },
- "amperage": {
- "type": "integer"
- },
- "numberOfConnectedPhase": {
- "type": "integer",
- "enum": [1, 3]
- },
- "chargePointID": {
- "type": "integer"
- }
- },
- "additionalProperties": false,
- "required": [
- "connectorId",
- "type",
- "power",
- "chargePointID"
- ]
- }
}
},
- "additionalProperties": false,
"required": [
- "maximumPower",
- "voltage",
- "powerLimitUnit",
- "chargePoints",
- "connectors"
- ]
- },
- "capabilities": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "supportedFirmwareVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "supportedOcppVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "capabilities": {
- "type": "object",
- "properties": {
- "supportStaticLimitation": {
- "type": "boolean"
- },
- "supportChargingProfiles": {
- "type": "boolean"
- },
- "supportRemoteStartStopTransaction": {
- "type": "boolean"
- },
- "supportUnlockConnector": {
- "type": "boolean"
- },
- "supportReservation": {
- "type": "boolean"
- },
- "supportCreditCard": {
- "type": "boolean"
- },
- "supportRFIDCard": {
- "type": "boolean"
- }
- },
- "additionalProperties": false,
- "required": [
- "supportStaticLimitation",
- "supportChargingProfiles",
- "supportRemoteStartStopTransaction",
- "supportUnlockConnector",
- "supportReservation",
- "supportCreditCard",
- "supportRFIDCard"
- ]
- }
- },
- "additionalProperties": false,
- "required": [
- "supportedFirmwareVersions",
- "supportedOcppVersions",
- "capabilities"
- ]
- }
- },
- "ocppStandardParameters": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "supportedFirmwareVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "supportedOcppVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "parameters": {
- "type": "object",
- "properties": {
- "AllowOfflineTxForUnknownId": {
- "type": "string"
- },
- "AuthorizationCacheEnabled": {
- "type": "string"
- },
- "AuthorizeRemoteTxRequests": {
- "type": "string"
- },
- "BlinkRepeat": {
- "type": "string"
- },
- "ClockAlignedDataInterval": {
- "type": "string"
- },
- "ConnectionTimeOut": {
- "type": "string"
- },
- "GetConfigurationMaxKeys": {
- "type": "string"
- },
- "HeartbeatInterval": {
- "type": "string"
- },
- "LightIntensity": {
- "type": "string"
- },
- "LocalAuthorizeOffline": {
- "type": "string"
- },
- "LocalPreAuthorize": {
- "type": "string"
- },
- "MaxEnergyOnInvalidId": {
- "type": "string"
- },
- "MeterValuesAlignedData": {
- "type": "string"
- },
- "MeterValuesAlignedDataMaxLength": {
- "type": "string"
- },
- "MeterValuesSampledData": {
- "type": "string"
- },
- "MeterValuesSampledDataMaxLength": {
- "type": "string"
- },
- "MeterValueSampleInterval": {
- "type": "string"
- },
- "MinimumStatusDuration": {
- "type": "string"
- },
- "NumberOfConnectors": {
- "type": "string"
- },
- "ResetRetries": {
- "type": "string"
- },
- "ConnectorPhaseRotation": {
- "type": "string"
- },
- "ConnectorPhaseRotationMaxLength": {
- "type": "string"
- },
- "StopTransactionOnEVSideDisconnect": {
- "type": "string"
- },
- "StopTransactionOnInvalidId": {
- "type": "string"
- },
- "StopTxnAlignedData": {
- "type": "string"
- },
- "StopTxnAlignedDataMaxLength": {
- "type": "string"
- },
- "StopTxnSampledData": {
- "type": "string"
- },
- "StopTxnSampledDataMaxLength": {
- "type": "string"
- },
- "SupportedFeatureProfiles": {
- "type": "string"
- },
- "SupportedFeatureProfilesMaxLength": {
- "type": "string"
- },
- "TransactionMessageAttempts": {
- "type": "string"
- },
- "TransactionMessageRetryInterval": {
- "type": "string"
- },
- "UnlockConnectorOnEVSideDisconnect": {
- "type": "string"
- },
- "WebSocketPingInterval": {
- "type": "string"
- },
- "LocalAuthListEnabled": {
- "type": "string"
- },
- "LocalAuthListMaxLength": {
- "type": "string"
- },
- "SendLocalListMaxLength": {
- "type": "string"
- },
- "ReserveConnectorZeroSupported": {
- "type": "string"
- },
- "ChargeProfileMaxStackLevel": {
- "type": "string"
- },
- "ChargingScheduleAllowedChargingRateUnit": {
- "type": "string"
- },
- "ChargingScheduleMaxPeriods": {
- "type": "string"
- },
- "ConnectorSwitch3to1PhaseSupported": {
- "type": "string"
- },
- "MaxChargingProfilesInstalled": {
- "type": "string"
- }
- },
- "additionalProperties": false,
- "anyOf": [
- { "required": ["AllowOfflineTxForUnknownId"] },
- { "required": ["AuthorizationCacheEnabled"] },
- { "required": ["AuthorizeRemoteTxRequests"] },
- { "required": ["BlinkRepeat"] },
- { "required": ["ClockAlignedDataInterval"] },
- { "required": ["ConnectionTimeOut"] },
- { "required": ["GetConfigurationMaxKeys"] },
- { "required": ["HeartbeatInterval"] },
- { "required": ["LightIntensity"] },
- { "required": ["LocalAuthorizeOffline"] },
- { "required": ["LocalPreAuthorize"] },
- { "required": ["MaxEnergyOnInvalidId"] },
- { "required": ["MeterValuesAlignedData"] },
- { "required": ["MeterValuesAlignedDataMaxLength"] },
- { "required": ["MeterValuesSampledData"] },
- { "required": ["MeterValuesSampledDataMaxLength"] },
- { "required": ["MeterValueSampleInterval"] },
- { "required": ["MinimumStatusDuration"] },
- { "required": ["NumberOfConnectors"] },
- { "required": ["ResetRetries"] },
- { "required": ["ConnectorPhaseRotation"] },
- { "required": ["ConnectorPhaseRotationMaxLength"] },
- { "required": ["StopTransactionOnEVSideDisconnect"] },
- { "required": ["StopTransactionOnInvalidId"] },
- { "required": ["StopTxnAlignedData"] },
- { "required": ["StopTxnAlignedDataMaxLength"] },
- { "required": ["StopTxnSampledData"] },
- { "required": ["StopTxnSampledDataMaxLength"] },
- { "required": ["SupportedFeatureProfiles"] },
- { "required": ["SupportedFeatureProfilesMaxLength"] },
- { "required": ["TransactionMessageAttempts"] },
- { "required": ["TransactionMessageRetryInterval"] },
- { "required": ["UnlockConnectorOnEVSideDisconnect"] },
- { "required": ["WebSocketPingInterval"] },
- { "required": ["LocalAuthListEnabled"] },
- { "required": ["LocalAuthListMaxLength"] },
- { "required": ["SendLocalListMaxLength"] },
- { "required": ["ReserveConnectorZeroSupported"] },
- { "required": ["ChargeProfileMaxStackLevel"] },
- { "required": ["ChargingScheduleAllowedChargingRateUnit"] },
- { "required": ["ChargingScheduleMaxPeriods"] },
- { "required": ["ConnectorSwitch3to1PhaseSupported"] },
- { "required": ["MaxChargingProfilesInstalled"] }
- ]
- }
- },
- "additionalProperties": false,
- "required": [
- "supportedFirmwareVersions",
- "supportedOcppVersions",
- "parameters"
- ]
- }
- },
- "ocppVendorParameters": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "supportedFirmwareVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "supportedOcppVersions": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "parameters": {
- "type": "object",
- "patternProperties": {
- ".*": {
- "type": "string"
- }
- }
- }
- },
- "additionalProperties": false,
- "required": [
- "supportedFirmwareVersions",
- "supportedOcppVersions",
- "parameters"
- ]
- }
- }
- },
- "additionalProperties": false,
- "required": [
- "chargePointVendor",
- "technical",
- "capabilities",
+ "id",
"hash",
"hashTechnical",
"hashCapabilities",
"hashOcppVendor"
]
}
\ No newline at end of file
- },
- "required": [
- "id"
- ]
-}
\ No newline at end of file

MODIFY
src/migration/tasks/AddLevelTemplateToChargingStationTemplateTask.ts
src/migration/tasks/AddLevelTemplateToChargingStationTemplateTask.ts
@@ -16,7 +16,14 @@ export default class AddLevelTemplateToChargingStationTemplateTask extends Migra
if (!Utils.isEmptyArray(templates)) {
for (const template of templates) {
// Put _id in id const and get template without id
- const { ['_id']: id, ...noIdTemplate } = template;
+ const {
+ ['_id']: id,
+ ['hash']: hash,
+ ['hashTechnical']: hashTechnical,
+ ['hashCapabilities']: hashCapabilities,
+ ['hashOcppStandard']: hashOcppStandard,
+ ['hashOcppVendor']: hashOcppVendor,
+ ...noIdTemplate } = template;
// Delete template
await global.database.getCollection<any>(Constants.DEFAULT_TENANT_ID, 'chargingstationtemplates').findOneAndDelete(
// Find and delete by current id
@@ -28,6 +35,11 @@ export default class AddLevelTemplateToChargingStationTemplateTask extends Migra
_id: new ObjectId(),
lastChangedOn: new Date(),
template : noIdTemplate,
+ hash,
+ hashTechnical,
+ hashCapabilities,
+ hashOcppStandard,
+ hashOcppVendor,
},
);
}

MODIFY
src/server/ocpp/utils/OCPPUtils.ts
src/server/ocpp/utils/OCPPUtils.ts
@@ -809,8 +809,7 @@ export default class OCPPUtils {
const chargingStationTemplate = await OCPPUtils.getChargingStationTemplate(chargingStation);
if (chargingStationTemplate) {
// Handle connector
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'connectors') &&
- !Utils.isEmptyArray(chargingStationTemplate.template.technical.connectors)) {
+ if (!Utils.isEmptyArray(chargingStationTemplate.template.technical?.connectors)) {
let foundTemplateConnector: ChargingStationTemplateConnector;
// Master/Slave: Always take the first
if (chargingStationTemplate.template.technical.masterSlave) {
@@ -1527,7 +1526,7 @@ export default class OCPPUtils {
const chargingStationTemplate = await OCPPUtils.getChargingStationTemplate(chargingStation);
if (chargingStationTemplate) {
// Already updated?
- if (chargingStation.templateHash !== chargingStationTemplate.template.hash) {
+ if (chargingStation.templateHash !== chargingStationTemplate.hash) {
await Logging.logInfo({
...LoggingHelper.getChargingStationProperties(chargingStation),
tenantID: tenant.id,
@@ -1549,7 +1548,7 @@ export default class OCPPUtils {
templateUpdateResult.ocppVendorUpdated =
await OCPPUtils.enrichChargingStationWithTemplateOcppVendorParams(tenant, chargingStation, chargingStationTemplate);
// Update
- chargingStation.templateHash = chargingStationTemplate.template.hash;
+ chargingStation.templateHash = chargingStationTemplate.hash;
templateUpdateResult.chargingStationUpdated = true;
await Logging.logInfo({
...LoggingHelper.getChargingStationProperties(chargingStation),
@@ -1592,8 +1591,8 @@ export default class OCPPUtils {
private static async enrichChargingStationWithTemplateOcppStandardParams(tenant: Tenant, chargingStation: ChargingStation,
chargingStationTemplate: ChargingStationTemplate): Promise<boolean> {
// Already updated?
- if (chargingStation.templateHashOcppStandard !== chargingStationTemplate.template.hashOcppStandard) {
- chargingStation.templateHashOcppStandard = chargingStationTemplate.template.hashOcppStandard;
+ if (chargingStation.templateHashOcppStandard !== chargingStationTemplate.hashOcppStandard) {
+ chargingStation.templateHashOcppStandard = chargingStationTemplate.hashOcppStandard;
return OCPPUtils.enrichChargingStationWithTemplateOcppParams(tenant, chargingStation, chargingStationTemplate, 'ocppStandardParameters');
}
}
@@ -1601,8 +1600,8 @@ export default class OCPPUtils {
private static async enrichChargingStationWithTemplateOcppVendorParams(tenant: Tenant, chargingStation: ChargingStation,
chargingStationTemplate: ChargingStationTemplate): Promise<boolean> {
// Already updated?
- if (chargingStation.templateHashOcppVendor !== chargingStationTemplate.template.hashOcppVendor) {
- chargingStation.templateHashOcppVendor = chargingStationTemplate.template.hashOcppVendor;
+ if (chargingStation.templateHashOcppVendor !== chargingStationTemplate.hashOcppVendor) {
+ chargingStation.templateHashOcppVendor = chargingStationTemplate.hashOcppVendor;
return OCPPUtils.enrichChargingStationWithTemplateOcppParams(tenant, chargingStation, chargingStationTemplate, 'ocppVendorParameters');
}
}
@@ -1611,7 +1610,7 @@ export default class OCPPUtils {
ocppProperty: 'ocppStandardParameters'|'ocppVendorParameters'): Promise<boolean> {
// Handle OCPP Standard Parameters
chargingStation[ocppProperty] = [];
- if (Utils.objectHasProperty(chargingStationTemplate, ocppProperty)) {
+ if (chargingStationTemplate.template?.[ocppProperty]) {
let matchFirmware = false;
let matchOcpp = false;
// Search Firmware/Ocpp match
@@ -1678,10 +1677,10 @@ export default class OCPPUtils {
private static async enrichChargingStationWithTemplateCapabilities(tenant: Tenant, chargingStation: ChargingStation,
chargingStationTemplate: ChargingStationTemplate): Promise<boolean> {
// Already updated?
- if (chargingStation.templateHashCapabilities !== chargingStationTemplate.template.hashCapabilities) {
+ if (chargingStation.templateHashCapabilities !== chargingStationTemplate.hashCapabilities) {
// Handle capabilities
chargingStation.capabilities = {} as ChargingStationCapabilities;
- if (Utils.objectHasProperty(chargingStationTemplate, 'capabilities')) {
+ if (chargingStationTemplate.template?.capabilities) {
let matchFirmware = false;
let matchOcpp = false;
// Search Firmware/Ocpp match
@@ -1702,12 +1701,11 @@ export default class OCPPUtils {
}
// Found?
if (matchFirmware && matchOcpp) {
- if (Utils.objectHasProperty(capabilities.capabilities, 'supportChargingProfiles') &&
- !capabilities.capabilities?.supportChargingProfiles) {
+ if (capabilities.capabilities?.supportChargingProfiles === false) {
chargingStation.excludeFromSmartCharging = !capabilities.capabilities.supportChargingProfiles;
}
chargingStation.capabilities = capabilities.capabilities;
- chargingStation.templateHashCapabilities = chargingStationTemplate.template.hashCapabilities;
+ chargingStation.templateHashCapabilities = chargingStationTemplate.hashCapabilities;
return true;
}
}
@@ -1725,24 +1723,24 @@ export default class OCPPUtils {
}
private static enrichChargingStationWithTemplateTechnicalParams(chargingStation: ChargingStation, chargingStationTemplate: ChargingStationTemplate): boolean {
- if (chargingStation.templateHashTechnical !== chargingStationTemplate.template.hashTechnical) {
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'maximumPower')) {
+ if (chargingStation.templateHashTechnical !== chargingStationTemplate.hashTechnical) {
+ if (chargingStationTemplate.template.technical?.maximumPower) {
chargingStation.maximumPower = chargingStationTemplate.template.technical.maximumPower;
}
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'masterSlave')) {
+ if (chargingStationTemplate.template.technical?.masterSlave) {
chargingStation.masterSlave = chargingStationTemplate.template.technical.masterSlave;
}
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'chargePoints')) {
+ if (chargingStationTemplate.template.technical?.chargePoints) {
chargingStation.chargePoints = chargingStationTemplate.template.technical.chargePoints;
}
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'powerLimitUnit')) {
+ if (chargingStationTemplate.template.technical?.powerLimitUnit) {
chargingStation.powerLimitUnit = chargingStationTemplate.template.technical.powerLimitUnit;
}
- if (Utils.objectHasProperty(chargingStationTemplate.template.technical, 'voltage')) {
+ if (chargingStationTemplate.template.technical?.voltage) {
chargingStation.voltage = chargingStationTemplate.template.technical.voltage;
}
// Set the hash
- chargingStation.templateHashTechnical = chargingStationTemplate.template.hashTechnical;
+ chargingStation.templateHashTechnical = chargingStationTemplate.hashTechnical;
return true;
}
}

MODIFY
src/server/rest/v1/service/ChargingStationTemplateService.ts
src/server/rest/v1/service/ChargingStationTemplateService.ts
@@ -25,11 +25,6 @@ export default class ChargingStationTemplateService {
createdBy: { id: req.user.id },
createdOn: new Date(),
template : {
- hash : Utils.hash(JSON.stringify(filteredRequest)),
- hashTechnical : Utils.hash(JSON.stringify(filteredRequest.template.technical)),
- hashCapabilities : Utils.hash(JSON.stringify(filteredRequest.template.capabilities)),
- hashOcppStandard : Utils.hash(JSON.stringify(filteredRequest.template.ocppStandardParameters)),
- hashOcppVendor : Utils.hash(JSON.stringify(filteredRequest.template.ocppVendorParameters)),
chargePointVendor: filteredRequest.template.chargePointVendor,
capabilities: filteredRequest.template.capabilities,
ocppStandardParameters: filteredRequest.template.ocppStandardParameters,
@@ -121,11 +116,6 @@ export default class ChargingStationTemplateService {
req.tenant, req.user, filteredRequest.id, Action.UPDATE, action, filteredRequest, { withUser: true });
const template = filteredRequest.template;
chargingStationTemplate.template = {
- hash: Utils.hash(JSON.stringify(filteredRequest)),
- hashTechnical: Utils.hash(JSON.stringify(template.technical)),
- hashCapabilities: Utils.hash(JSON.stringify(template.capabilities)),
- hashOcppStandard: Utils.hash(JSON.stringify(template.ocppStandardParameters)),
- hashOcppVendor: Utils.hash(JSON.stringify(template.ocppVendorParameters)),
chargePointVendor: template.chargePointVendor,
extraFilters: template.extraFilters,
technical: template.technical,

MODIFY
src/storage/mongodb/ChargingStationTemplateStorage.ts
src/storage/mongodb/ChargingStationTemplateStorage.ts
@@ -17,6 +17,11 @@ export default class ChargingStationTemplateStorage {
const startTime = Logging.traceDatabaseRequestStart();
// Validate
const chargingStationTemplateMDB = ChargingStationValidatorStorage.getInstance().validateChargingStationTemplateSave(chargingStationTemplate);
+ chargingStationTemplateMDB.hash = Utils.hash(JSON.stringify(chargingStationTemplateMDB)),
+ chargingStationTemplateMDB.hashTechnical = Utils.hash(JSON.stringify(chargingStationTemplateMDB.template.technical)),
+ chargingStationTemplateMDB.hashCapabilities = Utils.hash(JSON.stringify(chargingStationTemplateMDB.template.capabilities)),
+ chargingStationTemplateMDB.hashOcppStandard = Utils.hash(JSON.stringify(chargingStationTemplateMDB.template.ocppStandardParameters)),
+ chargingStationTemplateMDB.hashOcppVendor = Utils.hash(JSON.stringify(chargingStationTemplateMDB.template.ocppVendorParameters)),
DatabaseUtils.switchIDToMongoDBID(chargingStationTemplateMDB);
// Add Last Changed/Created props
DatabaseUtils.addLastChangedCreatedProps(chargingStationTemplateMDB, chargingStationTemplate);

MODIFY
src/types/ChargingStation.ts
src/types/ChargingStation.ts
@@ -225,12 +225,12 @@ export enum Voltage {
export interface ChargingStationTemplate extends CreatedUpdatedProps, AuthorizationActions {
id: string;
- template: {
hash?: string;
hashTechnical?: string;
hashCapabilities?: string;
hashOcppStandard?: string;
hashOcppVendor?: string;
+ template: {
chargePointVendor: string;
extraFilters: {
chargePointModel: string;

moved hashes outside template level in charging station template type
+ aligned code