From 7e18eeeddbd0a45c9d494ebbe5019509134ba05e Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Sun, 5 May 2024 23:07:29 +0700 Subject: [PATCH 1/6] fix bug --- app/components/evse.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/evse.tsx b/app/components/evse.tsx index c1a83cc..e3f9037 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -77,7 +77,7 @@ export default function Evse() {
From ba8a78101757b994ffbbdc99fb1aafe1c6eb3b5d Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Sun, 5 May 2024 23:12:22 +0700 Subject: [PATCH 2/6] comply with CSMS --- app/components/evse.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/evse.tsx b/app/components/evse.tsx index e3f9037..c1a83cc 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -77,7 +77,7 @@ export default function Evse() {
From 1e34e144baae19f8d8506c22e2429e0ea3f59dbf Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Sun, 5 May 2024 23:14:25 +0700 Subject: [PATCH 3/6] comply with ocpp --- app/components/evse.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/evse.tsx b/app/components/evse.tsx index c1a83cc..a40babf 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -16,7 +16,7 @@ import { SendStatusNotification } from '../service/ocpp/command/status-notificat import Transaction from './transaction'; const defaultValue = 'ws://localhost:8080/ocpp/JwNpTpPxPm/CHR202305102'; - +const connectorId = 1; export default function Evse() { const [url, setUrl] = useState(defaultValue); const [online, setOnline] = useState(false); @@ -77,7 +77,7 @@ export default function Evse() {
From d330704b7a4f787b74ffa665265cfb5178097d3e Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Sun, 5 May 2024 23:16:44 +0700 Subject: [PATCH 4/6] Fix connector id ocpp conflict --- app/components/evse.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/evse.tsx b/app/components/evse.tsx index a40babf..ef9c5c4 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -48,7 +48,7 @@ export default function Evse() { if (writer.current[0] == null) return; SendStatusNotification( writer.current[0], - 0, + connectorId, error ?? ChargePointErrorCodes.NoError, state ); From c65fd0bbac605c0e6284f0dd75b1044748a29ef7 Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Mon, 6 May 2024 00:59:39 +0700 Subject: [PATCH 5/6] can remote start transaction --- app/components/evse.tsx | 20 +++++--- app/components/transaction.tsx | 4 +- .../charging/start.transaction.model.ts | 0 .../charging/start.transaction.ts | 14 ++--- .../charging/stop.transaction.model.ts | 0 .../charging/stop.transaction.ts | 10 ++-- .../remote/remote.start.transaction.model.ts | 29 +++++++++++ .../remote/remote.start.transaction.ts | 51 +++++++++++++++++++ app/service/ocpp/ocpp.action.list.ts | 23 +++++++++ app/service/ocpp/ocpp.handler.ts | 17 +++++-- 10 files changed, 143 insertions(+), 25 deletions(-) rename app/service/ocpp/{ => command}/charging/start.transaction.model.ts (100%) rename app/service/ocpp/{ => command}/charging/start.transaction.ts (78%) rename app/service/ocpp/{ => command}/charging/stop.transaction.model.ts (100%) rename app/service/ocpp/{ => command}/charging/stop.transaction.ts (73%) create mode 100644 app/service/ocpp/command/remote/remote.start.transaction.model.ts create mode 100644 app/service/ocpp/command/remote/remote.start.transaction.ts create mode 100644 app/service/ocpp/ocpp.action.list.ts diff --git a/app/components/evse.tsx b/app/components/evse.tsx index ef9c5c4..75b9057 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -1,6 +1,6 @@ 'use client'; -import { SyntheticEvent, useRef, useState } from 'react'; +import { SyntheticEvent, useEffect, useRef, useState } from 'react'; import Input from './input'; import { ConState, IWriter } from '../service/websocket/websocket.model'; import WebSocket from './WebSocket'; @@ -21,7 +21,9 @@ export default function Evse() { const [url, setUrl] = useState(defaultValue); const [online, setOnline] = useState(false); const writer = useRef>([]); - const [socket, setSocket] = useState(new ChargingSocket()); + const [socket, setSocket] = useState>([ + new ChargingSocket(), + ]); const onlineChange: ConState = (connected: boolean, w?: IWriter) => { setOnline(connected); @@ -35,16 +37,17 @@ export default function Evse() { setUrl(event.currentTarget.value); }; - const onMessage = (ev: MessageEvent) => { + const onMessage: (ev: MessageEvent) => void = (ev: MessageEvent) => { if (writer == null) return; - HandleOcpp(writer.current[0], ev.data, changeState); + HandleOcpp(writer.current[0], ev.data, socket[0].State, changeState); }; const changeState = ( state: StatusNotification, error?: ChargePointErrorCodes ) => { - setSocket({ ...socket, State: state }); + socket[0].State = state; + setSocket([...socket]); if (writer.current[0] == null) return; SendStatusNotification( writer.current[0], @@ -71,14 +74,17 @@ export default function Evse() { onMessage={onMessage} online={online} /> - +
diff --git a/app/components/transaction.tsx b/app/components/transaction.tsx index 0476fa6..182eb1b 100644 --- a/app/components/transaction.tsx +++ b/app/components/transaction.tsx @@ -2,12 +2,12 @@ import React, { SyntheticEvent, useState } from 'react'; import { GetSession, SendStartTransaction, -} from '../service/ocpp/charging/start.transaction'; +} from '../service/ocpp/command/charging/start.transaction'; import Input from './input'; import Button from './button'; import { IWriter } from '../service/websocket/websocket.model'; import { StatusNotification } from '../service/ocpp/command/status-notification/status.notification'; -import { SendStopTransaction } from '../service/ocpp/charging/stop.transaction'; +import { SendStopTransaction } from '../service/ocpp/command/charging/stop.transaction'; import { ChangeState } from '../service/ocpp/ocpp.handler'; import Select, { ReturnValue } from './select'; diff --git a/app/service/ocpp/charging/start.transaction.model.ts b/app/service/ocpp/command/charging/start.transaction.model.ts similarity index 100% rename from app/service/ocpp/charging/start.transaction.model.ts rename to app/service/ocpp/command/charging/start.transaction.model.ts diff --git a/app/service/ocpp/charging/start.transaction.ts b/app/service/ocpp/command/charging/start.transaction.ts similarity index 78% rename from app/service/ocpp/charging/start.transaction.ts rename to app/service/ocpp/command/charging/start.transaction.ts index 415f92c..7a7911b 100644 --- a/app/service/ocpp/charging/start.transaction.ts +++ b/app/service/ocpp/command/charging/start.transaction.ts @@ -1,17 +1,17 @@ import Validate from '@/app/helper/validation.helper'; -import { IWriter } from '../../websocket/websocket.model'; -import { Action, CreateRequestFrame, GetRequestFrame } from '../ocpp.action'; -import { CreateError, ErrorCode } from '../ocpp.error'; -import { IResponse } from '../ocpp.frame'; -import { ChangeState } from '../ocpp.handler'; -import { CreateTransaction } from '../transaction/transaction.handler'; +import { IWriter } from '../../../websocket/websocket.model'; +import { Action, CreateRequestFrame, GetRequestFrame } from '../../ocpp.action'; +import { CreateError, ErrorCode } from '../../ocpp.error'; +import { IResponse } from '../../ocpp.frame'; +import { ChangeState } from '../../ocpp.handler'; +import { CreateTransaction } from '../../transaction/transaction.handler'; import { AuthorizationStatus, IChargingSession, IStartTransaction, StartTransactionsRes, } from './start.transaction.model'; -import { StatusNotification } from '../command/status-notification/status.notification'; +import { StatusNotification } from '../status-notification/status.notification'; let session: IChargingSession; diff --git a/app/service/ocpp/charging/stop.transaction.model.ts b/app/service/ocpp/command/charging/stop.transaction.model.ts similarity index 100% rename from app/service/ocpp/charging/stop.transaction.model.ts rename to app/service/ocpp/command/charging/stop.transaction.model.ts diff --git a/app/service/ocpp/charging/stop.transaction.ts b/app/service/ocpp/command/charging/stop.transaction.ts similarity index 73% rename from app/service/ocpp/charging/stop.transaction.ts rename to app/service/ocpp/command/charging/stop.transaction.ts index 164a53b..bb254b2 100644 --- a/app/service/ocpp/charging/stop.transaction.ts +++ b/app/service/ocpp/command/charging/stop.transaction.ts @@ -1,8 +1,8 @@ -import { IWriter } from '../../websocket/websocket.model'; -import { StatusNotification } from '../command/status-notification/status.notification'; -import { Action, CreateRequestFrame, GetRequestFrame } from '../ocpp.action'; -import { ChangeState } from '../ocpp.handler'; -import { CreateTransaction } from '../transaction/transaction.handler'; +import { IWriter } from '../../../websocket/websocket.model'; +import { StatusNotification } from '../status-notification/status.notification'; +import { Action, CreateRequestFrame, GetRequestFrame } from '../../ocpp.action'; +import { ChangeState } from '../../ocpp.handler'; +import { CreateTransaction } from '../../transaction/transaction.handler'; import { ResetSession } from './start.transaction'; import { IStopTransaction } from './stop.transaction.model'; diff --git a/app/service/ocpp/command/remote/remote.start.transaction.model.ts b/app/service/ocpp/command/remote/remote.start.transaction.model.ts new file mode 100644 index 0000000..a717683 --- /dev/null +++ b/app/service/ocpp/command/remote/remote.start.transaction.model.ts @@ -0,0 +1,29 @@ +import { IsOptional, IsString, Min, Max } from 'class-validator'; + +enum Status { + ACCEPTED = 'Accepted', + REJECTED = 'Rejected', +} + +interface IRemoteStartTransactionRes { + status: Status; +} + +interface IRemoteStartTransaction { + connectorId: number; + idTag: string; +} + +class RemoteStartTransaction implements IRemoteStartTransaction { + @Min(0) + @Max(1) + @IsOptional() + connectorId: number = 0; + @IsString() + idTag: string = ''; + @IsOptional() + chargingProfile: unknown; +} + +export type { IRemoteStartTransactionRes, IRemoteStartTransaction }; +export { RemoteStartTransaction, Status }; diff --git a/app/service/ocpp/command/remote/remote.start.transaction.ts b/app/service/ocpp/command/remote/remote.start.transaction.ts new file mode 100644 index 0000000..c4ec33b --- /dev/null +++ b/app/service/ocpp/command/remote/remote.start.transaction.ts @@ -0,0 +1,51 @@ +import { IWriter } from '@/app/service/websocket/websocket.model'; +import { IRequest } from '../../ocpp.frame'; +import { StatusNotification } from '../status-notification/status.notification'; +import { CreateResponseFrame } from '../../ocpp.action'; +import { + IRemoteStartTransaction, + IRemoteStartTransactionRes, + RemoteStartTransaction, + Status, +} from './remote.start.transaction.model'; +import { SendStartTransaction } from '../charging/start.transaction'; +import Validate from '@/app/helper/validation.helper'; +import { CreateError, ErrorCode } from '../../ocpp.error'; + +export function RemoteStartTransactionReq( + w: IWriter, + frame: IRequest, + state: StatusNotification +): void { + console.log(state); + + let status: IRemoteStartTransactionRes = { status: Status.REJECTED }; + if ( + state == StatusNotification.AVAILABLE || + state == StatusNotification.PREPARING || + state == StatusNotification.FINISHING + ) { + const [result, validation] = Validate( + RemoteStartTransaction, + frame.payload + ); + + if (validation.length > 0) { + w.Write(CreateError(ErrorCode.PropertyConstraintViolation, validation)); + return; + } + + if (result.connectorId == 0) { + result.connectorId = 1; + } + + status.status = Status.ACCEPTED; + SendStartTransaction(w, result.connectorId, result.idTag); + } + + const response = CreateResponseFrame( + frame.uuid, + status + ); + w.Write(response); +} diff --git a/app/service/ocpp/ocpp.action.list.ts b/app/service/ocpp/ocpp.action.list.ts new file mode 100644 index 0000000..eb23069 --- /dev/null +++ b/app/service/ocpp/ocpp.action.list.ts @@ -0,0 +1,23 @@ +import { IWriter } from '../websocket/websocket.model'; +import { RemoteStartTransactionReq } from './command/remote/remote.start.transaction'; +import { StatusNotification } from './command/status-notification/status.notification'; +import { Action } from './ocpp.action'; +import { ErrorCode } from './ocpp.error'; +import { IRequest } from './ocpp.frame'; + +type ActionItem = { + name: string; + handel: (w: IWriter, frame: IRequest, state: StatusNotification) => void; +}; + +const List: Array = [ + { name: Action.REMOTE_START_TRANSACTION, handel: RemoteStartTransactionReq }, +]; + +function FindAction(action: string): ActionItem { + const handler = List.find((a) => a.name == action); + if (handler == null) throw new Error(ErrorCode.NotImplemented); + return handler; +} + +export { FindAction }; diff --git a/app/service/ocpp/ocpp.handler.ts b/app/service/ocpp/ocpp.handler.ts index d4dd2ac..5162013 100644 --- a/app/service/ocpp/ocpp.handler.ts +++ b/app/service/ocpp/ocpp.handler.ts @@ -2,6 +2,7 @@ import { IWriter } from '../websocket/websocket.model'; import { GetRequestFrame, GetResponseFrame } from './ocpp.action'; import { CreateError, ErrorCode, GetError } from './ocpp.error'; import { + Action, BaseTuple, CallType, IErrorFrame, @@ -13,6 +14,7 @@ import { StatusNotification, } from './command/status-notification/status.notification'; import { FindTransaction } from './transaction/transaction.handler'; +import { FindAction } from './ocpp.action.list'; type OCPPData = IRequest | IResponse | IErrorFrame; type ChangeState = ( @@ -44,8 +46,13 @@ function getFullFrame(frame: BaseTuple): [CallType, OCPPData] { return [callType, data]; } -function processCall(frame: IRequest) { - console.log(frame); +function processCall( + w: IWriter, + frame: IRequest, + state: StatusNotification +): void { + const handler = FindAction(frame.action); + handler.handel(w, frame, state); } function processReturn( @@ -68,11 +75,12 @@ function processReturn( function handleFrame( w: IWriter, frame: BaseTuple, + state: StatusNotification, changeState: ChangeState ): void { const [call, result] = getFullFrame(frame); if (call == CallType.CALL) { - processCall(result as IRequest); + processCall(w, result as IRequest, state); } else { processReturn(w, result, changeState); } @@ -97,13 +105,14 @@ function handlerError(err: Error, w: IWriter): void { export function HandleOcpp( w: IWriter, json: string, + state: StatusNotification, changeState: ChangeState ): void { try { const data: unknown = JSON.parse(json); if (!Array.isArray(data)) throw new Error(ErrorCode.ProtocolError); let frame = isValidFrame(data); - handleFrame(w, frame, changeState); + handleFrame(w, frame, state, changeState); } catch (error: unknown) { handlerError(error as Error, w); } From 3f7cd82ce54904d38198afd9f4b70a7b1b74407c Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Mon, 6 May 2024 01:00:20 +0700 Subject: [PATCH 6/6] fix build bugs --- app/components/evse.tsx | 2 +- app/service/ocpp/ocpp.handler.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/components/evse.tsx b/app/components/evse.tsx index 75b9057..0e2c8b5 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -1,6 +1,6 @@ 'use client'; -import { SyntheticEvent, useEffect, useRef, useState } from 'react'; +import { SyntheticEvent, useRef, useState } from 'react'; import Input from './input'; import { ConState, IWriter } from '../service/websocket/websocket.model'; import WebSocket from './WebSocket'; diff --git a/app/service/ocpp/ocpp.handler.ts b/app/service/ocpp/ocpp.handler.ts index 5162013..623141e 100644 --- a/app/service/ocpp/ocpp.handler.ts +++ b/app/service/ocpp/ocpp.handler.ts @@ -2,7 +2,6 @@ import { IWriter } from '../websocket/websocket.model'; import { GetRequestFrame, GetResponseFrame } from './ocpp.action'; import { CreateError, ErrorCode, GetError } from './ocpp.error'; import { - Action, BaseTuple, CallType, IErrorFrame,