Skip to content

Commit

Permalink
Add regular OCPP heartbeat
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix Manke committed Oct 17, 2021
1 parent 5bf21dc commit 1e61b93
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 14 deletions.
3 changes: 3 additions & 0 deletions src/lib/wallbox-simulator/ConnectButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { Writable } from 'svelte/store';
import Button from '../components/Button.svelte';
import { startHeartbeat, stopHeartbeat } from './heatbeatTrigger';
import type { ConnectionState } from './store';
import { connectStation, disconnectStation } from './websocket';
Expand Down Expand Up @@ -50,8 +51,10 @@
setErrorMessage,
addLogMessage
);
startHeartbeat(webSocket);
} else if ($connectionState === 'connected') {
webSocket = disconnectStation(webSocket, setConnectionState);
stopHeartbeat();
}
}
</script>
Expand Down
56 changes: 56 additions & 0 deletions src/lib/wallbox-simulator/heatbeatTrigger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { HeartbeatRequest } from "./ocpp/messages/heartBeat";

const DEFAULT_INTERVAL_SECONDS = 300;

let heartbeatTimer: NodeJS.Timeout;

/**
* Start sending OCPP hearbeat messages in regular intervals (default: every 5 minutes).
*
* @param intervalSeconds The interval (in seconds) for the OCPP heartbeat message to be sent.
*/
export function startHeartbeat(
websocket: WebSocket,
intervalSeconds = DEFAULT_INTERVAL_SECONDS
) {
heartbeatTimer = setTimeout(function () {
sendHeartbeatMessage(websocket);
}, intervalSeconds * 1000);

console.log(`OCPP Heartbeat initialized with ${intervalSeconds} seconds.`);
}

/**
* Reset the timer for the OCPP heartbeat message. Trigger this, whenever you send any other OCPP
* message to the backend.
*
* (Reasoning: the heartbeat message should only be sent after the wallbox has been idling for the
* specified amount of time...).
*
* @param intervalSeconds The interval (in seconds) for the OCPP heartbeat message to be sent.
*/
export function resetHeartbeatTimer(
websocket: WebSocket,
intervalSeconds = DEFAULT_INTERVAL_SECONDS
) {
stopHeartbeat();
startHeartbeat(websocket, intervalSeconds);
}

/**
* Clears the OCPP heartbeat timer so that the wallbox simulator stops sending heartbeat messages.
*/
export function stopHeartbeat() {
if (heartbeatTimer) {
clearTimeout(heartbeatTimer);
}
heartbeatTimer = undefined;
console.log(`OCPP Heartbeat timer cleared.`);
}

/**
* Sends an OCPP heartbeat message.
*/
function sendHeartbeatMessage(websocket: WebSocket) {
HeartbeatRequest(websocket, {});
}
20 changes: 8 additions & 12 deletions src/lib/wallbox-simulator/ocpp/messages/bootNotification.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import type { BootNotificationRequestType } from "../types/bootNotificationRequestType";
import { OcppCallMessageBuilder } from "./ocppMessage";

/**
* ### 1.2. BootNotification
*
* Sent by the wallbox to the CSMS after booting.
*/
export const BootNotification =
OcppCallMessageBuilder<BootNotificationPayload>("BootNotification");
OcppCallMessageBuilder<BootNotificationRequestType>("BootNotification");

export type BootNotificationPayload = {
chargingStation: {
serialNumber: string;
model: string;
vendorName: string;
firmwareVersion: string;
};
reason: string;
};

export const defaultBootNotificationPayload: BootNotificationPayload = {
export const defaultBootNotificationPayload: BootNotificationRequestType = {
chargingStation: {
serialNumber: "SOME-serial-NUMBER-123",
model: "MGWB Fake",
Expand Down
12 changes: 12 additions & 0 deletions src/lib/wallbox-simulator/ocpp/messages/heartBeat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { OcppCallMessageBuilder } from "./ocppMessage";

export type HeartBeatRequestPayload = {};

/**
* ### 1.29.1. HeartbeatRequest
*
* This contains the field definition of the HeartbeatRequest PDU sent by the
* Charging Station to the CSMS. No fields are defined.
*/
export const HeartbeatRequest =
OcppCallMessageBuilder<HeartBeatRequestPayload>("Heartbeat");
11 changes: 9 additions & 2 deletions src/lib/wallbox-simulator/ocpp/messages/ocppMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { v4 as uuidv4 } from "uuid";
import { resetHeartbeatTimer } from "../../heatbeatTrigger";

/**
* Specifies the nature of any OCPP message. To identify the type of message one
Expand All @@ -12,9 +13,12 @@ export enum OcppMessageType {

/**
* List of OCCP actions implemented & supported by the simulator.
*
*/
const ocppActions = ["BootNotification", "TransactionEvent"] as const;
const ocppActions = [
"BootNotification",
"Heartbeat",
"TransactionEvent",
] as const;
export type OcppAction = typeof ocppActions[number];

/**
Expand Down Expand Up @@ -72,8 +76,11 @@ export function OcppCallMessageBuilder<PayloadType>(
]);

console.log(`Sending ${ocppActionType}.`);

resetHeartbeatTimer(websocket);
websocket.send(ocppMessage);
sessionStorage.setItem("LastAction", ocppActionType);

console.log(`${ocppActionType} sent!`);
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { BootReasonEnumType } from "./bootReasonEnumType";
import type { ChargingStationType } from "./chargingStationType";

/**
* ### 1.2.1. BootNotificationRequest
*
* This contains the field definition of the BootNotificationRequest PDU sent by
* the Charging Station to the CSMS.
*/
export type BootNotificationRequestType = {
reason: BootReasonEnumType;
chargingStation: ChargingStationType;
};
19 changes: 19 additions & 0 deletions src/lib/wallbox-simulator/ocpp/types/bootReasonEnumType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* ### 2.5. BootReasonEnumType
* _Enumeration_
*
* BootReasonEnumType is used by: `bootNotification:BootNotificationRequest`
*/
export type BootReasonEnumType = typeof bootReasons[number];

export const bootReasons = [
"ApplicationReset", // The Charging Station rebooted due to an application error.
"FirmwareUpdate", // The Charging Station rebooted due to a firmware update.
"LocalReset", // The Charging Station rebooted due to a local reset command.
"PowerUp", // The Charging Station powered up and registers itself with the CSMS.
"RemoteReset", // The Charging Station rebooted due to a remote reset command.
"ScheduledReset", // The Charging Station rebooted due to a scheduled reset command.
"Triggered", // Requested by the CSMS via a TriggerMessage
"Unknown", // The boot reason is unknown.
"Watchdog", // The Charging Station rebooted due to an elapsed watchdog timer.
] as const;
14 changes: 14 additions & 0 deletions src/lib/wallbox-simulator/ocpp/types/chargingStationType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* ### 1.13. ChargingStationType
* _Class_
*
* The physical system where an Electrical Vehicle (EV) can be charged.
* ChargingStationType is used by: _BootNotificationRequest_
*/
export type ChargingStationType = {
serialNumber?: string; // string[0..20] 0..1 Optional. Vendor-specific device identifier.
model: string; // string[0..20] 1..1 Required. Defines the model of the device.
vendorName: string; // string[0..50] 1..1 Required. Identifies the vendor (not necessarily in a unique manner).
firmwareVersion?: string; // string[0..50] 0..1 Optional. This contains the firmware version of the Charging Station.
modem?: any; // ModemType 0..1 Optional. Defines the functional
};

0 comments on commit 1e61b93

Please sign in to comment.