Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start charging implemented #26

Merged
merged 2 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/components/WebSocket.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
OnMessageEvent,
} from '../service/websocket/websocket.model';
import WebSocketHook from '../hook/socketHook';
import Button from './button';

type Url = {
url: string;
Expand Down Expand Up @@ -35,12 +36,11 @@ export default function WebSocket({

return (
<div>
<button
className='border border-blue-600 rounded-md px-4 py-2 my-4'
onClick={() => start()}
>
{online ? 'Disconnect' : 'Connect'}
</button>
<Button
onClick={start}
text={online ? 'Disconnect' : 'Connect'}
disabled={false}
/>
</div>
);
}
18 changes: 18 additions & 0 deletions app/components/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
type button = {
text: string;
disabled: boolean;
onClick: () => void;
};

export default function Button({ text, disabled, onClick }: button) {
const disable = disabled ? 'bg-gray-400' : '';
return (
<button
className={`${disable} border border-blue-600 rounded-md px-4 py-2 my-4`}
onClick={() => onClick()}
disabled={disabled}
>
{text}
</button>
);
}
38 changes: 28 additions & 10 deletions app/components/evse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import { ConState, IWriter } from '../service/websocket/websocket.model';
import WebSocket from './WebSocket';
import { ChargingSocket, IChargingSocket } from '../service/ocpp/connector';
import { HandleOcpp } from '../service/ocpp/ocpp.handler';
import { SendBootNotification } from '../service/ocpp/command/boot-notification/bootnotification';
import { SendBootNotification } from '../service/ocpp/command/boot-notification/boot.notification';
import StatusNotificationUI from './status.notification';
import {
ChargePointErrorCodes,
StatusNotification,
} from '../service/ocpp/command/status-notification/status.notificiation';
} from '../service/ocpp/command/status-notification/status.notification';
import { SendStatusNotification } from '../service/ocpp/command/status-notification/statusnotification';
import Transaction from './transaction';

const defaultValue = 'ws://localhost:8080/ocpp/JwNpTpPxPm/CHR202305102';

Expand Down Expand Up @@ -55,14 +56,31 @@ export default function Evse() {

return (
<div className='w-screen mx-auto mt-8 md:w-2/3 xl:w-1/3'>
<Input name='url' value={url} onChange={onChange} disabled={online} />
<WebSocket
url={url}
state={onlineChange}
onMessage={onMessage}
online={online}
/>
<StatusNotificationUI state={socket.State} changeState={changeState} />
<div className='border border-black p-2 my-2 rounded-md'>
<Input
title='Websocket Url'
name='url'
placeholder='wss://'
value={url}
onChange={onChange}
disabled={online}
/>
<WebSocket
url={url}
state={onlineChange}
onMessage={onMessage}
online={online}
/>
<StatusNotificationUI state={socket.State} changeState={changeState} />
</div>

<div className={online ? '' : 'hidden'}>
<Transaction
writer={writer.current[0]}
connectorId={0}
state={socket.State}
/>
</div>
</div>
);
}
8 changes: 6 additions & 2 deletions app/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ import { SyntheticEvent } from 'react';
type InputEvent = (event: SyntheticEvent<HTMLInputElement>) => void;

type input = {
title: string;
name: string;
value: string;
placeholder: string;
disabled: boolean;
onChange: InputEvent;
};

export default function Input({
title,
name,
value,
placeholder,
disabled,
onChange,
}: input): JSX.Element {
return (
<div className='px-4'>
<label className='block text-sm font-medium leading-6 text-gray-900'>
Websocket Url
{title}
</label>
<div className='relative mt-2 rounded-md shadow-sm'>
<input
Expand All @@ -27,7 +31,7 @@ export default function Input({
defaultValue={value}
onChange={onChange}
className='block w-full rounded-md border-0 py-1.5 pl-7 pr-20 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
placeholder='wss://'
placeholder={placeholder}
disabled={disabled}
/>
</div>
Expand Down
4 changes: 1 addition & 3 deletions app/components/status.notification.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { StatusNotification } from '../service/ocpp/command/status-notification/status.notificiation';
import { StatusNotification } from '../service/ocpp/command/status-notification/status.notification';
import { ChangeState } from '../service/ocpp/ocpp.handler';
import Select, { Item, ReturnValue } from './select';

Expand All @@ -20,8 +20,6 @@ export default function StatusNotificationUI({
const onChange = (value: ReturnValue) =>
changeState(value as StatusNotification);

console.log(state);

return (
<div>
state: {state}
Expand Down
81 changes: 81 additions & 0 deletions app/components/transaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { SyntheticEvent, useState } from 'react';
import { SendStartTransaction } from '../service/ocpp/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';

type transaction = {
writer: IWriter;
connectorId: number;
state: StatusNotification;
};

export default function Transaction({
writer,
connectorId,
state,
}: transaction): React.JSX.Element {
const [idTag, setIdTag] = useState('cli013322');
const onChange = (ev: SyntheticEvent<HTMLInputElement>) => {
setIdTag(ev.currentTarget.value);
};

const notConnected = () => {
if (writer == null) {
alert('Please connect to CSMS');
}
};

const onStart = () => {
if (writer == null) {
notConnected();
return;
}

if (
state == StatusNotification.AVAILABLE ||
state == StatusNotification.PREPARING
) {
if (idTag.trim() == '') return;
SendStartTransaction(writer, connectorId, idTag);
return;
}

alert(
'Please make sure that the charger is in Available or preparing state'
);
};

const onStop = () => {
if (writer == null) {
notConnected();
return;
}
};

return (
<div className='border border-black p-2 my-2 rounded-md'>
<Input
title='Client id tag'
name='idTag'
placeholder='enter ID tag to submit with start transaction'
value={idTag}
onChange={onChange}
disabled={false}
/>
<div className='grid gap-2 grid-cols-2'>
<Button
onClick={onStart}
text='Start Transaction'
disabled={state == StatusNotification.CHARGING}
/>
<Button
onClick={onStop}
text='Stop Transaction'
disabled={state != StatusNotification.CHARGING}
/>
</div>
</div>
);
}
52 changes: 52 additions & 0 deletions app/service/ocpp/charging/start.transaction.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Min } from 'class-validator';

enum AuthorizationStatus {
ACCEPTED = 'Accepted',
BLOCKED = 'Blocked',
EXPIRED = 'Expired',
INVALID = 'Invalid',
CONCURRENT_TX = 'ConcurrentTx',
}

interface IIdTagInfo {
expiryDate: Date;
parentIdTag: string;
status: string;
}

interface IStartTransactionRes {
idTagInfo: IIdTagInfo;
transactionId: number;
}

interface IStartTransaction {
connectorId: number;
idTag: string;
meterStart: number;
timestamp: Date;
}

interface IChargingSession {
idTag: string;
transactionId: number;
connectorId: number;
}

class StartTransactionsRes implements IStartTransactionRes {
idTagInfo: IIdTagInfo = {
expiryDate: new Date(),
status: AuthorizationStatus.BLOCKED,
parentIdTag: '',
};

@Min(0)
transactionId: number = 0;
}

export type {
IIdTagInfo,
IStartTransaction,
IStartTransactionRes,
IChargingSession,
};
export { AuthorizationStatus, StartTransactionsRes };
60 changes: 60 additions & 0 deletions app/service/ocpp/charging/start.transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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 {
AuthorizationStatus,
IChargingSession,
IStartTransaction,
StartTransactionsRes,
} from './start.transaction.model';
import { StatusNotification } from '../command/status-notification/status.notification';

let session: IChargingSession;

function SendStartTransaction(
w: IWriter,
connectorId: number,
idTag: string
): void {
const transaction: IStartTransaction = {
connectorId,
idTag,
meterStart: 0,
timestamp: new Date(),
};

const frame = CreateRequestFrame(Action.START_TRANSACTION, transaction);
w.Write(frame);
CreateTransaction(GetRequestFrame(frame), StartTransaction);
session = { connectorId, idTag, transactionId: -1 };
}

function StartTransaction(
w: IWriter,
frame: IResponse,
changeState: ChangeState
): IChargingSession | undefined {
const [result, validation] = Validate<StartTransactionsRes>(
StartTransactionsRes,
frame.payload
);

if (validation.length > 0) {
w.Write(CreateError(ErrorCode.PropertyConstraintViolation, validation));
return;
}

if (result.idTagInfo.status != AuthorizationStatus.ACCEPTED) {
return;
}

changeState(StatusNotification.CHARGING);
session.transactionId = result.transactionId;
return session;
}

export { SendStartTransaction, StartTransaction };
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import {
BootNotificationRes,
IBootNotification,
Status,
} from './bootnotification.model';
} from './boot.notification.model';
import { CreateError, ErrorCode } from '../../ocpp.error';
import Validate from '@/app/helper/validation.helper';
import { StatusNotification } from '../status-notification/status.notificiation';
import { StatusNotification } from '../status-notification/status.notification';
import { ChangeState } from '../../ocpp.handler';

const defaultValue: IBootNotification = {
Expand Down Expand Up @@ -60,8 +60,6 @@ function BootNotification(
frame.payload
);

console.log(validation);

if (validation.length > 0) {
w.Write(CreateError(ErrorCode.PropertyConstraintViolation, validation));
return retry(w);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ChargePointErrorCodes,
IStatusNotification,
StatusNotification,
} from './status.notificiation';
} from './status.notification';

function SendStatusNotification(
w: IWriter,
Expand Down
2 changes: 1 addition & 1 deletion app/service/ocpp/connector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StatusNotification } from './command/status-notification/status.notificiation';
import { StatusNotification } from './command/status-notification/status.notification';

interface IChargingSocket {
State: StatusNotification;
Expand Down
2 changes: 1 addition & 1 deletion app/service/ocpp/ocpp.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import {
ChargePointErrorCodes,
StatusNotification,
} from './command/status-notification/status.notificiation';
} from './command/status-notification/status.notification';
import { FindTransaction } from './transaction/transaction.handler';

type OCPPData = IRequest | IResponse | IErrorFrame;
Expand Down
Loading