Skip to content

Commit

Permalink
Merge pull request #25 from Nasar165/statusnotification
Browse files Browse the repository at this point in the history
Statusnotification
  • Loading branch information
Nasar165 authored May 5, 2024
2 parents 7681439 + bcbbdd3 commit a7cab33
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 97 deletions.
31 changes: 23 additions & 8 deletions app/components/evse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import Input from './input';
import { ConState, IWriter } from '../service/websocket/websocket.model';
import WebSocket from './WebSocket';
import { ChargingSocket, IChargingSocket } from '../service/ocpp/connector';
import { StatusNotification } from '../service/ocpp/status.notificiation';
import { HandleOcpp } from '../service/ocpp/ocpp.handler';
import { SendBootNotification } from '../service/ocpp/command/boot-notification/bootnotification';
import StatusNotificationUI from './status.notification';
import {
ChargePointErrorCodes,
StatusNotification,
} from '../service/ocpp/command/status-notification/status.notificiation';
import { SendStatusNotification } from '../service/ocpp/command/status-notification/statusnotification';

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

export default function Evse() {
const [url, setUrl] = useState(defaultValue);
const [online, setOnline] = useState(false);
const writer = useRef<Array<IWriter>>([]);

const chargingSocket = useRef<IChargingSocket>(
new ChargingSocket(StatusNotification.UNAVAILABLE)
);
const [socket, setSocket] = useState<IChargingSocket>(new ChargingSocket());

const onlineChange: ConState = (connected: boolean, w?: IWriter) => {
console.log(chargingSocket);

setOnline(connected);
if (w != null) {
writer.current.push(w);
Expand All @@ -36,7 +36,21 @@ export default function Evse() {

const onMessage = (ev: MessageEvent) => {
if (writer == null) return;
HandleOcpp(writer.current[0], ev.data);
HandleOcpp(writer.current[0], ev.data, changeState);
};

const changeState = (
state: StatusNotification,
error?: ChargePointErrorCodes
) => {
setSocket({ ...socket, State: state });
if (writer.current[0] == null) return;
SendStatusNotification(
writer.current[0],
0,
error ?? ChargePointErrorCodes.NoError,
state
);
};

return (
Expand All @@ -48,6 +62,7 @@ export default function Evse() {
onMessage={onMessage}
online={online}
/>
<StatusNotificationUI state={socket.State} changeState={changeState} />
</div>
);
}
100 changes: 100 additions & 0 deletions app/components/select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { useEffect, useState } from 'react';

type ReturnValue = string | number;

type Item = {
name: string;
value: ReturnValue;
};

type Select = {
items: Array<Item>;
defaultItem: Item;
onChange: (value: ReturnValue) => void;
};

function Selected(item: Item, selected?: Item) {
if (selected == null || item.name != selected.name) return null;
return (
<span className='text-indigo-600 absolute inset-y-0 right-0 flex items-center pr-4'>
<svg
className='h-5 w-5'
viewBox='0 0 20 20'
fill='currentColor'
aria-hidden='true'
>
<path d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z' />
</svg>
</span>
);
}

export default function Select({
items,
defaultItem,
onChange,
}: Select): React.JSX.Element {
const [selected, setSelected] = useState<Item>();
const [drop, setDrop] = useState(false);
const show = drop ? '' : 'hidden';

const onClick = (item: Item) => {
setSelected(item);
onChange(item.value);
onDrop();
};

const onDrop = () => {
setDrop((v) => !v);
};

useEffect(() => {
setSelected(defaultItem);
}, [defaultItem]);

return (
<div>
<div className='relative mt-2'>
<button
onClick={onDrop}
type='button'
className=' relative w-full cursor-default rounded-md bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm sm:leading-6'
>
<span className='flex items-center'>
<span className='ml-3 block truncate'>
{selected == null ? null : selected.name}
</span>
</span>
<span className='pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2'>
<svg className='h-5 w-5 text-gray-400' viewBox='0 0 20 20'>
<path d='M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z' />
</svg>
</span>
</button>
<ul
className={`${show} absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm`}
role='listbox'
aria-labelledby='listbox-label'
aria-activedescendant='listbox-option-3'
>
{items.map((item) => (
<li
onClick={() => onClick(item)}
key={item.name}
className='text-gray-900 relative cursor-default select-none py-2 pl-3 pr-9'
>
<div className='flex items-center'>
<span className='font-normal ml-3 block truncate'>
{item.name}
</span>
</div>
{Selected(item, selected)}
</li>
))}
</ul>
</div>
</div>
);
}

export type { Item, ReturnValue };
31 changes: 31 additions & 0 deletions app/components/status.notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { StatusNotification } from '../service/ocpp/command/status-notification/status.notificiation';
import { ChangeState } from '../service/ocpp/ocpp.handler';
import Select, { Item, ReturnValue } from './select';

type State = {
state: StatusNotification;
changeState: ChangeState;
};

export default function StatusNotificationUI({
state,
changeState,
}: State): React.JSX.Element {
const items: Array<Item> = Object.values(StatusNotification).map((v) => {
return { name: v, value: v };
});
const defaultState = { name: state, value: state };

const onChange = (value: ReturnValue) =>
changeState(value as StatusNotification);

console.log(state);

return (
<div>
state: {state}
<Select items={items} onChange={onChange} defaultItem={defaultState} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {
IsNumber,
IsEnum,
Min,
Max,
MinLength,
MaxLength,
IsOptional,
IsString,
} from 'class-validator';
import { IsNumber, IsEnum, Min, Max, IsString } from 'class-validator';

enum Status {
ACCEPTED = 'Accepted',
Expand All @@ -32,51 +23,6 @@ interface IBootNotificationRes {
status: Status;
}

class BootNotification implements IBootNotification {
@MinLength(1)
@MaxLength(20)
chargePointVendor = '';

@MinLength(1)
@MaxLength(20)
chargePointModel = '';

@MinLength(1)
@MaxLength(25)
@IsOptional()
chargeBoxSerialNumber = '';

@MinLength(1)
@MaxLength(25)
@IsOptional()
chargePointSerialNumber = '';

@MinLength(1)
@MaxLength(50)
@IsOptional()
firmwareVersion = '';

@MinLength(1)
@MaxLength(20)
@IsOptional()
iccid = '';

@MinLength(1)
@MaxLength(20)
@IsOptional()
imsi = '';

@MinLength(1)
@MaxLength(25)
@IsOptional()
meterSerialNumber = '';

@MinLength(1)
@MaxLength(25)
@IsOptional()
meterType = '';
}

class BootNotificationRes implements IBootNotificationRes {
@IsString()
currentTime: Date = new Date();
Expand All @@ -91,4 +37,4 @@ class BootNotificationRes implements IBootNotificationRes {
}

export type { IBootNotification };
export { Status, BootNotification, BootNotificationRes };
export { Status, BootNotificationRes };
14 changes: 10 additions & 4 deletions app/service/ocpp/command/boot-notification/bootnotification.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { DEFAULT_TIMER, IWriter } from '../../../websocket/websocket.model';
import { Action, CreateRequestFrame, GetRequestFrame } from '../../ocpp.action';
import { IResponse } from '../../ocpp.frame';
import { NewTransaction } from '../../transaction/transaction.handler';
import { CreateTransaction } from '../../transaction/transaction.handler';
import {
BootNotificationRes,
IBootNotification,
Status,
} from './bootnotification.model';
import { CreateError, ErrorCode } from '../../ocpp.error';
import Validate from '@/app/helper/validation.helper';
import { StatusNotification } from '../status-notification/status.notificiation';
import { ChangeState } from '../../ocpp.handler';

const defaultValue: IBootNotification = {
chargePointVendor: 'EW',
Expand Down Expand Up @@ -40,14 +42,18 @@ function SendBootNotification(w: IWriter): void {
clearTimeout(id);
if (success) return;
const frame = CreateRequestFrame(Action.BOOT_NOTIFICATION, defaultValue);
NewTransaction(GetRequestFrame(frame), BootNotification);
CreateTransaction(GetRequestFrame(frame), BootNotification);
w.Write(frame);
} catch (error) {
retry(w);
}
}

function BootNotification(w: IWriter, frame: IResponse): void {
function BootNotification(
w: IWriter,
frame: IResponse,
changeState: ChangeState
): void {
clearTimeout(id);
const [result, validation] = Validate<BootNotificationRes>(
BootNotificationRes,
Expand All @@ -74,7 +80,7 @@ function BootNotification(w: IWriter, frame: IResponse): void {
if (result.status == Status.REJECTED) {
return retry(w);
}

changeState(StatusNotification.AVAILABLE);
success = true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
enum StatusNotification {
AVAILABLE = 'Available',
PREPARING = 'Preparing',
CHARGING = 'Charging',
SUSPENDED_EVSE = 'SuspendedEVSE',
SUSPENDED_EV = 'SuspendedEV',
FINISHING = 'Finishing',
RESERVED = 'Reserved',
UNAVAILABLE = 'Unavailable',
FAULTED = 'Faulted',
}

enum ChargePointErrorCodes {
ConnectorLockFailure = 'NoError',
EVCommunicationError = 'EVCommunicationError',
GroundFailure = 'GroundFailure',
HighTemperature = 'HighTemperature',
InternalError = 'InternalError',
LocalListConflict = 'LocalListConflict',
NoError = 'NoError',
OtherError = 'OtherError',
OverCurrentFailure = 'OverCurrentFailure',
OverVoltage = 'OverVoltage',
PowerMeterFailure = 'PowerMeterFailure',
PowerSwitchFailure = 'PowerSwitchFailure',
ReaderFailure = 'ReaderFailure',
ResetFailure = 'ResetFailure',
UnderVoltage = 'UnderVoltage',
WeakSignal = 'WeakSignal',
}

interface IStatusNotification {
connectorId: number;
status: StatusNotification;
errorCode: ChargePointErrorCodes;
}

export type { IStatusNotification };
export { ChargePointErrorCodes, StatusNotification };
30 changes: 30 additions & 0 deletions app/service/ocpp/command/status-notification/statusnotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { IWriter } from '../../../websocket/websocket.model';
import { Action, CreateRequestFrame, GetRequestFrame } from '../../ocpp.action';
import { CreateTransaction } from '../../transaction/transaction.handler';
import {
ChargePointErrorCodes,
IStatusNotification,
StatusNotification,
} from './status.notificiation';

function SendStatusNotification(
w: IWriter,
connectorId: number,
errorCode: ChargePointErrorCodes,
status: StatusNotification
): void {
const req: IStatusNotification = {
connectorId,
errorCode,
status,
};
const frame = CreateRequestFrame(Action.STATUS_NOTIFICATION, req);
w.Write(frame);
CreateTransaction(GetRequestFrame(frame), StatusNotificationRes);
}

function StatusNotificationRes(): void {
console.log('status notification res received');
}

export { SendStatusNotification };
Loading

0 comments on commit a7cab33

Please sign in to comment.