From: Sekiya Date: Wed, 5 Jun 2024 14:03:50 +0000 (+0900) Subject: Add missing types for GetBaseReport payload handling X-Git-Tag: v1.3.7~87^2~1 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=fa16d389b8eb171e581c3fe5789602c54ac85ab1;p=e-mobility-charging-stations-simulator.git Add missing types for GetBaseReport payload handling --- diff --git a/tests/ocpp-server/README.md b/tests/ocpp-server/README.md new file mode 100644 index 00000000..e02d8b7b --- /dev/null +++ b/tests/ocpp-server/README.md @@ -0,0 +1,40 @@ +# OCPP2 Mock Server + +This project includes a mock Open Charge Point Protocol (OCPP) version 2.0.1 server implemented in Python. + +## Prerequisites + +This project requires Python 3.7+ and the following Python packages: + +- `websockets` +- `ocpp` + +You can install these packages using pip: +``` +pip install websockets ocpp +``` + +## Running the Server + +To start the server, run the `server.py` script: + +``` +python server.py +``` + +The server will start listening for connections on port 9000. + +## Overview of the Server Scripts + +### Server.py + +The server script waits for connections from clients. When a client connects, the server creates a new instance of the `ChargePoint` class. This class includes methods for handling various OCPP actions (`BootNotification`,`GetBaseReport`), most of which return a dummy response. The `GetBaseReport` method prints the received request and returns a simple confirmation message. + +The server script uses the websockets and ocpp libraries to facilitate the WebSocket and OCPP communication. + +## Note + +Primarily, this software is intended for testing applications. The server scripts don't execute full OCPP adherence and it is advised not to use them in a production environment without additional development. + +For reference: +https://github.com/mobilityhouse/ocpp diff --git a/tests/ocpp-server/__init__.py b/tests/ocpp-server/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/ocpp-server/server.py b/tests/ocpp-server/server.py new file mode 100644 index 00000000..87bb2e30 --- /dev/null +++ b/tests/ocpp-server/server.py @@ -0,0 +1,89 @@ +import asyncio +import logging +import websockets +from datetime import datetime, timezone + +from ocpp.routing import on +from ocpp.v201 import ChargePoint as cp +from ocpp.v201 import call_result +from ocpp.v201.enums import RegistrationStatusType, GenericDeviceModelStatusType + +# Setting up the logging configuration to display debug level messages. +logging.basicConfig(level=logging.DEBUG) + +# Define a ChargePoint class inheriting from the OCPP 2.0.1 ChargePoint class. +class ChargePoint(cp): + # Define a handler for the BootNotification message. + @on('BootNotification') + async def on_boot_notification(self, charging_station, reason, **kwargs): + logging.info("Received BootNotification") + # Create and return a BootNotification response with the current time, + # an interval of 10 seconds, and an accepted status. + return call_result.BootNotification( + current_time = datetime.now(timezone.utc).isoformat(), + interval=10, + status=RegistrationStatusType.accepted + ) + + # Define a handler for the GetBaseReport message. + @on('GetBaseReport') + async def on_get_base_report(self, request_id, report_base, **kwargs): + try: + logging.info(f"Received GetBaseReport request with RequestId: {request_id} and ReportBase: {report_base}") + + # Create a mock response for demonstration purposes, indicating the report is accepted. + response = call_result.GetBaseReport( + status=GenericDeviceModelStatusType.accepted + ) + + logging.info(f"Sending GetBaseReport response: {response}") + return response + except Exception as e: + # Log any errors that occur while handling the GetBaseReport request. + logging.error(f"Error handling GetBaseReport request: {e}", exc_info=True) + # Return a rejected status in case of error. + return call_result.GetBaseReport( + status=GenericDeviceModelStatusType.rejected + ) + +# Function to handle new WebSocket connections. +async def on_connect(websocket, path): + """ For every new charge point that connects, create a ChargePoint instance and start listening for messages. """ + try: + requested_protocols = websocket.request_headers['Sec-WebSocket-Protocol'] + except KeyError: + logging.info("Client hasn't requested any Subprotocol. Closing Connection") + return await websocket.close() + + if websocket.subprotocol: + logging.info("Protocols Matched: %s", websocket.subprotocol) + else: + logging.warning('Protocols Mismatched | Expected Subprotocols: %s,' + ' but client supports %s | Closing connection', + websocket.available_subprotocols, + requested_protocols) + return await websocket.close() + + charge_point_id = path.strip('/') + cp = ChargePoint(charge_point_id, websocket) + + # Start the ChargePoint instance to listen for incoming messages. + await cp.start() + +# Main function to start the WebSocket server. +async def main(): + # Create the WebSocket server and specify the handler for new connections. + server = await websockets.serve( + on_connect, + '0.0.0.0', # Listen on all available interfaces. + 9000, # Port number. + subprotocols=['ocpp2.0.1'] # Specify the OCPP 2.0.1 subprotocol. + ) + logging.info("WebSocket Server Started") + # Wait for the server to close (runs indefinitely). + await server.wait_closed() + +# Entry point of the script. +if __name__ == '__main__': + # Run the main function to start the server. + asyncio.run(main())