diff --git a/app/components/evse.tsx b/app/components/evse.tsx index c1a83cc..0e2c8b5 100644 --- a/app/components/evse.tsx +++ b/app/components/evse.tsx @@ -16,12 +16,14 @@ 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); 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,20 +37,21 @@ 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], - 0, + connectorId, error ?? ChargePointErrorCodes.NoError, state ); @@ -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..623141e 100644 --- a/app/service/ocpp/ocpp.handler.ts +++ b/app/service/ocpp/ocpp.handler.ts @@ -13,6 +13,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 +45,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 +74,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 +104,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); }