Skip to content

Commit

Permalink
Merge pull request #206 from citrineos/rc-1.3.2
Browse files Browse the repository at this point in the history
Rc 1.3.2
  • Loading branch information
thanaParis authored Aug 1, 2024
2 parents 5d67bee + 126e3e8 commit 7659cea
Show file tree
Hide file tree
Showing 59 changed files with 858 additions and 565 deletions.
1 change: 0 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ jobs:

- name: Lint
run: npm run lint

2 changes: 1 addition & 1 deletion 00_Base/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@citrineos/base",
"version": "1.3.1",
"version": "1.3.2",
"description": "The base module for OCPP v2.0.1 including all interfaces. This module is not intended to be used directly, but rather as a dependency for other modules.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
6 changes: 2 additions & 4 deletions 00_Base/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,9 @@ import {
} from './ocpp/model/index';
import { CallAction } from './ocpp/rpc/message';

export interface OcppRequest {
}
export interface OcppRequest {}

export interface OcppResponse {
}
export interface OcppResponse {}

export const CALL_SCHEMA_MAP: Map<CallAction, object> = new Map<
CallAction,
Expand Down
3 changes: 2 additions & 1 deletion 00_Base/src/interfaces/modules/AbstractModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ export abstract class AbstractModule implements IModule {
}
} catch (error) {
this._logger.error('Failed handling message: ', error, message);
if (message.state === MessageState.Request) { // CallErrors are only emitted for Calls
if (message.state === MessageState.Request) {
// CallErrors are only emitted for Calls
this._logger.error('Sending CallError to ChargingStation...');
message.origin = MessageOrigin.ChargingStationManagementSystem;
if (error instanceof OcppError) {
Expand Down
5 changes: 4 additions & 1 deletion 00_Base/src/interfaces/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ export abstract class CrudRepository<T> extends EventEmitter {
* @param namespace - Optional namespace for the key.
* @returns A promise that resolves to the value associated with the key, or undefined if the key does not exist.
*/
abstract readByKey(key: string | number, namespace?: string): Promise<T | undefined>;
abstract readByKey(
key: string | number,
namespace?: string,
): Promise<T | undefined>;

/**
* Reads values from storage based on the given query.
Expand Down
6 changes: 5 additions & 1 deletion 00_Base/src/interfaces/router/AbstractRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ export abstract class AbstractMessageRouter implements IMessageRouter {
}
}

abstract onMessage(identifier: string, message: string, timestamp: Date): Promise<boolean>;
abstract onMessage(
identifier: string,
message: string,
timestamp: Date,
): Promise<boolean>;

abstract registerConnection(connectionIdentifier: string): Promise<boolean>;
abstract deregisterConnection(connectionIdentifier: string): Promise<boolean>;
Expand Down
10 changes: 7 additions & 3 deletions 00_Base/src/interfaces/router/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ export interface IMessageRouter extends IModule {
/**
* Receive a message from the Network Connection.
* Timestamp here should be when the message was received from the charger.
* If CitrineOS is running behind cloud infrastructure, it is optimal for the timestamp to be generated when the infrastructure receives the message rather than when CitrineOS is first notified.
* If CitrineOS is running behind cloud infrastructure, it is optimal for the timestamp to be generated when the infrastructure receives the message rather than when CitrineOS is first notified.
* Otherwise lag or outages could result in a desync, causing CitrineOS to process messages as if they had been generated long after the charging station actually sent them.
*
*
* @param identifier Unique identifier for the charging station, i.e. the stationId
* @param message The unvalidated, raw OCPP text, i.e. [2, "123", "Heartbeat", {}]
* @param timestamp Time at which the message was received from the charger.
*/
onMessage(identifier: string, message: string, timestamp: Date): Promise<boolean>;
onMessage(
identifier: string,
message: string,
timestamp: Date,
): Promise<boolean>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
// SPDX-License-Identifier: Apache 2.0

export interface UpdateChargingStationPasswordRequest {

stationId: string;
password?: string;
setOnCharger: boolean;

stationId: string;
password?: string;
setOnCharger: boolean;
}
53 changes: 36 additions & 17 deletions 00_Base/src/util/MeterValueUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { MeasurandEnumType, MeterValueType, ReadingContextEnumType, SampledValueType } from '../ocpp/model';
import {
MeasurandEnumType,
MeterValueType,
ReadingContextEnumType,
SampledValueType,
} from '../ocpp/model';

export class MeterValueUtils {
private static readonly validContexts = new Set([
Expand All @@ -16,18 +21,25 @@ export class MeterValueUtils {
public static getTotalKwh(meterValues: MeterValueType[]): number {
const filteredValues = this.filterValidMeterValues(meterValues);
const timestampToKwhMap = this.getTimestampToKwhMap(filteredValues);
const sortedValues = this.getSortedKwhByTimestampAscending(timestampToKwhMap);
const sortedValues =
this.getSortedKwhByTimestampAscending(timestampToKwhMap);
return this.calculateTotalKwh(sortedValues);
}

private static filterValidMeterValues(meterValues: MeterValueType[]): MeterValueType[] {
return meterValues.filter(mv =>
// When missing, context is by default Sample_Periodic by spec
!mv.sampledValue[0].context || this.validContexts.has(mv.sampledValue[0].context)
private static filterValidMeterValues(
meterValues: MeterValueType[],
): MeterValueType[] {
return meterValues.filter(
(mv) =>
// When missing, context is by default Sample_Periodic by spec
!mv.sampledValue[0].context ||
this.validContexts.has(mv.sampledValue[0].context),
);
}

private static getTimestampToKwhMap(meterValues: MeterValueType[]): Map<number, number> {
private static getTimestampToKwhMap(
meterValues: MeterValueType[],
): Map<number, number> {
const valuesMap = new Map<number, number>();
for (const meterValue of meterValues) {
const overallValue = this.findOverallValue(meterValue.sampledValue);
Expand All @@ -42,10 +54,13 @@ export class MeterValueUtils {
return valuesMap;
}

private static findOverallValue(sampledValues: SampledValueType[]): SampledValueType | undefined {
return sampledValues.find(sv =>
!sv.phase &&
sv.measurand === MeasurandEnumType.Energy_Active_Import_Register
private static findOverallValue(
sampledValues: SampledValueType[],
): SampledValueType | undefined {
return sampledValues.find(
(sv) =>
!sv.phase &&
sv.measurand === MeasurandEnumType.Energy_Active_Import_Register,
);
}

Expand All @@ -58,18 +73,22 @@ export class MeterValueUtils {
case 'WH':
case undefined:
powerOfTen -= 3;
break
break;
default:
throw new Error("Unknown unit for Energy.Active.Import.Register: " + unit);
throw new Error(
'Unknown unit for Energy.Active.Import.Register: ' + unit,
);
}

return overallValue.value * (10 ** powerOfTen);
return overallValue.value * 10 ** powerOfTen;
}

private static getSortedKwhByTimestampAscending(valuesMap: Map<number, number>): number[] {
private static getSortedKwhByTimestampAscending(
valuesMap: Map<number, number>,
): number[] {
return Array.from(valuesMap.entries())
.sort((a, b) => a[0] - b[0])
.map(entry => entry[1]);
.map((entry) => entry[1]);
}

private static calculateTotalKwh(sortedValues: number[]): number {
Expand All @@ -78,4 +97,4 @@ export class MeterValueUtils {
}
return sortedValues[sortedValues.length - 1] - sortedValues[0];
}
}
}
4 changes: 2 additions & 2 deletions 01_Data/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@citrineos/data",
"version": "1.3.1",
"version": "1.3.2",
"description": "The OCPP data module which includes all persistence layer implementation.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -27,7 +27,7 @@
"typescript": "^5.0.4"
},
"dependencies": {
"@citrineos/base": "1.3.1",
"@citrineos/base": "1.3.2",
"@types/sequelize": "^4.28.20",
"bcrypt": "^5.1.1",
"pg": "^8.11.3",
Expand Down
7 changes: 5 additions & 2 deletions 01_Data/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//
// SPDX-License-Identifier: Apache 2.0

export {IdTokenAdditionalInfo} from "./layers/sequelize/model/Authorization/IdTokenAdditionalInfo";
import { Transaction as SequelizeTransaction } from 'sequelize';
export { SequelizeTransaction };
export { IdTokenAdditionalInfo } from './layers/sequelize/model/Authorization/IdTokenAdditionalInfo';
export * as sequelize from './layers/sequelize';
export * from './interfaces';
export * from 'sequelize-typescript';
Expand All @@ -27,6 +29,7 @@ export {
IdToken,
IdTokenInfo,
AdditionalInfo,
StatusNotification,
SignatureAlgorithmEnumType,
SequelizeAuthorizationRepository,
SequelizeBootRepository,
Expand All @@ -42,4 +45,4 @@ export {
SequelizeTransactionEventRepository,
SequelizeVariableMonitoringRepository,
} from './layers/sequelize'; // TODO ensure all needed modules are properly exported
export {RepositoryStore} from './layers/sequelize/repository/RepositoryStore';
export { RepositoryStore } from './layers/sequelize/repository/RepositoryStore';
5 changes: 1 addition & 4 deletions 01_Data/src/interfaces/projections/schemas/TariffSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,5 @@
"type": "number"
}
},
"required": [
"currency",
"pricePerKwh"
]
"required": ["currency", "pricePerKwh"]
}
4 changes: 1 addition & 3 deletions 01_Data/src/interfaces/queries/Tariff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

import { QuerySchema } from '@citrineos/base';

export const TariffQuerySchema = QuerySchema([
['id', 'string'],
]);
export const TariffQuerySchema = QuerySchema([['id', 'string']]);

export interface TariffQueryString {
id?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import { QuerySchema } from '@citrineos/base';
export const UpdateChargingStationPasswordQuerySchema = QuerySchema([['callbackUrl', 'string']]);

export interface UpdateChargingStationPasswordQueryString {
callbackUrl?: string;
callbackUrl?: string;
}
6 changes: 5 additions & 1 deletion 01_Data/src/layers/sequelize/model/Authorization/IdToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// SPDX-License-Identifier: Apache 2.0

import { type CustomDataType, IdTokenEnumType, type IdTokenType, Namespace } from '@citrineos/base';
import { BelongsToMany, Column, DataType, Model, Table } from 'sequelize-typescript';
import { BelongsToMany, Column, DataType, HasOne, Model, Table } from 'sequelize-typescript';
import { AdditionalInfo } from './AdditionalInfo';
import { IdTokenAdditionalInfo } from './IdTokenAdditionalInfo';
import { Authorization } from './Authorization';

@Table
export class IdToken extends Model implements IdTokenType {
Expand All @@ -27,5 +28,8 @@ export class IdToken extends Model implements IdTokenType {
})
declare type: IdTokenEnumType;

@HasOne(() => Authorization)
declare authorization: Authorization;

declare customData?: CustomDataType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export class VariableAttribute extends Model implements VariableAttributeType {
})
declare constant?: boolean;


@Column({
type: DataType.DATE,
get() {
Expand Down
3 changes: 2 additions & 1 deletion 01_Data/src/layers/sequelize/model/Location/Location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { Namespace } from '@citrineos/base';
import { Column, DataType, HasMany, Model, Table } from 'sequelize-typescript';
import { ChargingStation } from './ChargingStation';
import { Point } from 'geojson';

/**
* Represents a location.
Expand Down Expand Up @@ -36,7 +37,7 @@ export class Location extends Model {
* [longitude, latitude]
*/
@Column(DataType.GEOMETRY('POINT'))
declare coordinates: [number, number];
declare coordinates: Point;

@HasMany(() => ChargingStation)
declare chargingPool: [ChargingStation, ...ChargingStation[]];
Expand Down
Loading

0 comments on commit 7659cea

Please sign in to comment.