Serie: ocpp
python
1018 righe
· Aggiornato 2026-02-03
client.py
ocpp/ocpp_implementation/ocpp/cp/client.py
"""
OCPP 2.1 CP (Charge Point) Client
This module implements the CP client that connects to a CSMS server
and handles charging operations, status reporting, and system management.
"""
import asyncio
import json
import uuid
from typing import Dict, Optional, Any, List
from datetime import datetime, timedelta
import websockets
from websockets.client import WebSocketClientProtocol
from websockets.exceptions import ConnectionClosed, WebSocketException
# Add the project root to the Python path
import sys
import os
project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
if project_root not in sys.path:
sys.path.insert(0, project_root)
from config.settings import get_settings
from config.logging_config import get_logger
from ocpp.base.message_types import (
OCPPMessage, MessageType, ActionType, OCPPRequest, OCPPResponse, OCPPError
)
from ocpp.base.exceptions import (
OCPPError, OCPPProtocolError, OCPPMessageError, OCPPAuthenticationError,
OCPPAuthorizationError, OCPPValidationError, OCPPNotImplementedError,
OCPPNotSupportedError, OCPPInternalError, OCPPTimeoutError,
OCPPConnectionError, OCPPTransactionError, OCPPChargingProfileError,
OCPPCertificateError, OCPPFirmwareError, OCPPConfigurationError,
OCPPReservationError, OCPPTariffError, OCPPMonitoringError,
OCPPReportingError, OCPPDisplayError, OCPPSecurityError,
OCPPDataTransferError, OCPPGenericError, create_ocpp_error
)
class CPClient:
"""
OCPP 2.1 CP (Charge Point) Client
This class implements the Charge Point client that connects to a CSMS server
and handles charging operations, status reporting, and system management.
"""
def __init__(self, station_id: Optional[str] = None):
"""
Initialize CP client
Args:
station_id: Charging station ID (if None, uses default from settings)
"""
self.settings = get_settings()
if station_id is None:
# Generate UUID-based station ID: CP{UUID.4Hex}
import uuid
self.station_id = f"CP{uuid.uuid4().hex[:4].upper()}"
else:
self.station_id = station_id
self.logger = get_logger(f"cp.client.{self.station_id}")
# Connection state
self.websocket: Optional[WebSocketClientProtocol] = None
self.is_connected = False
self.is_authenticated = False
self.connection_attempts = 0
self.last_heartbeat = datetime.now()
# Message handling
self.pending_messages: Dict[str, asyncio.Future] = {}
self.message_handlers: Dict[str, callable] = {}
self.message_task: Optional[asyncio.Task] = None
# Charging station state
self.station_info = {
"model": self.settings.cp.model,
"vendor_name": self.settings.cp.vendor_name,
"serial_number": self.settings.cp.serial_number,
"firmware_version": self.settings.cp.firmware_version,
"station_id": self.station_id # Add station ID to boot notification
}
# EVSE and connector state
self.evses: Dict[int, Dict[str, Any]] = {}
self.connectors: Dict[int, Dict[str, Any]] = {}
# Transaction state
self.active_transactions: Dict[str, Dict[str, Any]] = {}
self.transaction_counter = 0
# Charging profiles
self.charging_profiles: Dict[int, Dict[str, Any]] = {}
# Monitoring
self.monitoring_data: Dict[str, Any] = {}
# Security
self.security_events: List[Dict[str, Any]] = []
# Statistics
self.stats = {
"total_messages_sent": 0,
"total_messages_received": 0,
"total_transactions": 0,
"connection_time": None,
"last_message_time": None
}
self.logger.info(f"CP Client initialized for station {self.station_id}")
async def connect(self) -> None:
"""
Connect to CSMS server
This method establishes a WebSocket connection to the CSMS server
and performs the boot notification process.
"""
try:
self.logger.info(f"Connecting to CSMS at {self.settings.cp.csms_url}")
# Connect to WebSocket server
self.websocket = await websockets.connect(
self.settings.cp.csms_url,
ping_interval=self.settings.cp.heartbeat_interval,
ping_timeout=10,
max_size=1048576,
subprotocols=['ocpp2.1']
)
self.is_connected = True
self.connection_attempts = 0
self.stats["connection_time"] = datetime.now()
self.logger.info("Connected to CSMS server")
# Start message handling in background first
self.message_task = asyncio.create_task(self._handle_messages())
self.logger.info(f"Created message task: {self.message_task}")
# Send boot notification
await self._send_boot_notification()
self.logger.info("CP Client connected and ready")
except Exception as e:
self.logger.error(f"Failed to connect to CSMS: {str(e)}")
self.is_connected = False
raise OCPPConnectionError(f"Failed to connect: {str(e)}")
async def disconnect(self) -> None:
"""
Disconnect from CSMS server
This method closes the WebSocket connection and cleans up resources.
"""
try:
if self.websocket:
await self.websocket.close()
self.websocket = None
self.is_connected = False
self.is_authenticated = False
self.logger.info("Disconnected from CSMS server")
except Exception as e:
self.logger.error(f"Error disconnecting from CSMS: {str(e)}")
async def reconnect(self) -> None:
"""
Reconnect to CSMS server
This method attempts to reconnect to the CSMS server with
exponential backoff for failed attempts.
"""
while self.connection_attempts < self.settings.cp.max_reconnect_attempts:
try:
self.connection_attempts += 1
self.logger.info(f"Reconnection attempt {self.connection_attempts}")
await asyncio.sleep(min(2 ** self.connection_attempts, 60))
await self.connect()
return
except Exception as e:
self.logger.error(f"Reconnection attempt {self.connection_attempts} failed: {str(e)}")
self.logger.error("Maximum reconnection attempts reached")
raise OCPPConnectionError("Failed to reconnect after maximum attempts")
async def send_message(self, message: OCPPMessage) -> Optional[Dict[str, Any]]:
"""
Send a message to the CSMS server
Args:
message: OCPP message to send
Returns:
Response message if it's a request, None otherwise
"""
if not self.is_connected or not self.websocket:
raise OCPPConnectionError("Not connected to CSMS server")
try:
# Serialize message to JSON
message_data = message.model_dump()
# Add unique ID if not present
if not message_data.get("unique_id"):
message_data["unique_id"] = str(uuid.uuid4())
# Send message
message_json = json.dumps(message_data)
self.logger.info(f"Sending message JSON: {message_json}")
await self.websocket.send(message_json)
self.logger.log_ocpp_message(
message_type=message.action or "Unknown",
direction="request",
message=f"Sent message to CSMS",
charging_station_id=self.station_id
)
self.stats["total_messages_sent"] += 1
self.stats["last_message_time"] = datetime.now()
# If it's a request, wait for response
if message.message_type == MessageType.CALL:
unique_id = message_data["unique_id"]
future = asyncio.Future()
self.pending_messages[unique_id] = future
try:
# Wait for response with timeout
response = await asyncio.wait_for(future, timeout=self.settings.cp.message_timeout)
return response
except asyncio.TimeoutError:
self.pending_messages.pop(unique_id, None)
raise OCPPTimeoutError("Timeout waiting for response from CSMS")
finally:
self.pending_messages.pop(unique_id, None)
return None
except Exception as e:
self.logger.error(f"Failed to send message to CSMS: {str(e)}")
raise OCPPConnectionError(f"Failed to send message: {str(e)}")
async def _handle_messages(self) -> None:
"""Handle incoming messages from CSMS server"""
self.logger.info("Starting message handling loop")
try:
async for message in self.websocket:
try:
self.logger.info(f"Received raw message from CSMS: {message}")
message_data = json.loads(message)
self.logger.info(f"Parsed message data: {message_data}")
await self._process_message(message_data)
self.stats["total_messages_received"] += 1
self.stats["last_message_time"] = datetime.now()
except json.JSONDecodeError as e:
self.logger.error(f"Invalid JSON message from CSMS: {str(e)}")
except Exception as e:
self.logger.error(f"Error processing message from CSMS: {str(e)}")
except ConnectionClosed:
self.logger.info("Connection to CSMS closed")
self.is_connected = False
except Exception as e:
self.logger.error(f"Error handling messages from CSMS: {str(e)}")
self.is_connected = False
async def _process_message(self, message_data: Dict[str, Any]) -> None:
"""
Process incoming message from CSMS
Args:
message_data: Parsed message data
"""
try:
message_type = message_data.get("message_type")
unique_id = message_data.get("unique_id")
action = message_data.get("action")
payload = message_data.get("payload", {})
self.logger.log_ocpp_message(
message_type=action or "Unknown",
direction="response" if message_type == MessageType.CALL_RESULT else "request",
message=f"Received message from CSMS",
charging_station_id=self.station_id
)
# Handle different message types
if message_type == MessageType.CALL:
# Handle request from CSMS
response = await self._handle_request(action, payload)
if response is not None:
await self._send_response(unique_id, response)
elif message_type == MessageType.CALL_RESULT:
# Handle response from CSMS
await self._handle_response(unique_id, payload)
elif message_type == MessageType.CALL_ERROR:
# Handle error from CSMS
await self._handle_error(unique_id, payload)
else:
raise OCPPProtocolError(f"Invalid message type: {message_type}")
except Exception as e:
self.logger.error(f"Error processing message from CSMS: {str(e)}")
await self._send_error(unique_id, "InternalError", str(e))
async def _handle_request(self, action: str, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""
Handle request from CSMS
Args:
action: Action name
payload: Request payload
Returns:
Response payload
"""
# Route to appropriate handler based on action
handler_map = {
ActionType.Authorize: self._handle_authorize,
ActionType.RequestStartTransaction: self._handle_request_start_transaction,
ActionType.RequestStopTransaction: self._handle_request_stop_transaction,
ActionType.SetChargingProfile: self._handle_set_charging_profile,
ActionType.ClearChargingProfile: self._handle_clear_charging_profile,
ActionType.GetChargingProfiles: self._handle_get_charging_profiles,
ActionType.ChangeAvailability: self._handle_change_availability,
ActionType.UnlockConnector: self._handle_unlock_connector,
ActionType.Reset: self._handle_reset,
ActionType.ClearCache: self._handle_clear_cache,
ActionType.UpdateFirmware: self._handle_update_firmware,
ActionType.SendLocalList: self._handle_send_local_list,
ActionType.GetLocalListVersion: self._handle_get_local_list_version,
ActionType.ReserveNow: self._handle_reserve_now,
ActionType.CancelReservation: self._handle_cancel_reservation,
ActionType.SecurityEventNotification: self._handle_security_event_notification,
ActionType.SignCertificate: self._handle_sign_certificate,
ActionType.CertificateSigned: self._handle_certificate_signed,
ActionType.GetInstalledCertificateIds: self._handle_get_installed_certificate_ids,
ActionType.DeleteCertificate: self._handle_delete_certificate,
ActionType.InstallCertificate: self._handle_install_certificate,
ActionType.GetCertificateStatus: self._handle_get_certificate_status,
ActionType.GetCertificateChainStatus: self._handle_get_certificate_chain_status,
ActionType.GetTariffs: self._handle_get_tariffs,
ActionType.SetDefaultTariff: self._handle_set_default_tariff,
ActionType.ClearTariffs: self._handle_clear_tariffs,
ActionType.SetDisplayMessage: self._handle_set_display_message,
ActionType.GetDisplayMessages: self._handle_get_display_messages,
ActionType.ClearDisplayMessage: self._handle_clear_display_message,
ActionType.SetVariableMonitoring: self._handle_set_variable_monitoring,
ActionType.ClearVariableMonitoring: self._handle_clear_variable_monitoring,
ActionType.SetMonitoringBase: self._handle_set_monitoring_base,
ActionType.SetMonitoringLevel: self._handle_set_monitoring_level,
ActionType.GetMonitoringReport: self._handle_get_monitoring_report,
ActionType.GetReport: self._handle_get_report,
ActionType.GetBaseReport: self._handle_get_base_report,
ActionType.TriggerMessage: self._handle_trigger_message,
ActionType.DataTransfer: self._handle_data_transfer,
ActionType.GetLog: self._handle_get_log,
ActionType.Get15118EVCertificate: self._handle_get_15118_ev_certificate,
}
handler = handler_map.get(action)
if handler:
return await handler(payload)
else:
raise OCPPNotSupportedError(f"Action not supported: {action}")
async def _handle_response(self, unique_id: str, payload: Dict[str, Any]) -> None:
"""
Handle response from CSMS
Args:
unique_id: Message unique ID
payload: Response payload
"""
self.logger.info(f"Handling response for unique_id: {unique_id}, payload: {payload}")
if unique_id in self.pending_messages:
future = self.pending_messages[unique_id]
if not future.done():
self.logger.info(f"Setting result for future {unique_id}")
future.set_result(payload)
else:
self.logger.warning(f"Future {unique_id} already done")
else:
self.logger.warning(f"No pending message found for unique_id: {unique_id}")
async def _handle_error(self, unique_id: str, payload: Dict[str, Any]) -> None:
"""
Handle error from CSMS
Args:
unique_id: Message unique ID
payload: Error payload
"""
if unique_id in self.pending_messages:
future = self.pending_messages[unique_id]
if not future.done():
error_code = payload.get("error_code", "UnknownError")
error_description = payload.get("error_description", "Unknown error")
error_details = payload.get("error_details", {})
error = create_ocpp_error(error_code, error_description, error_details)
future.set_exception(error)
async def _send_response(self, unique_id: str, payload: Dict[str, Any]) -> None:
"""
Send response to CSMS
Args:
unique_id: Message unique ID
payload: Response payload
"""
response = OCPPMessage(
message_type=MessageType.CALL_RESULT,
unique_id=unique_id,
payload=payload
)
await self.send_message(response)
async def _send_error(self, unique_id: str, error_code: str,
error_description: str, error_details: Optional[Dict[str, Any]] = None) -> None:
"""
Send error to CSMS
Args:
unique_id: Message unique ID
error_code: Error code
error_description: Error description
error_details: Additional error details
"""
error_payload = {
"error_code": error_code,
"error_description": error_description,
"error_details": error_details or {}
}
error_message = OCPPMessage(
message_type=MessageType.CALL_ERROR,
unique_id=unique_id,
payload=error_payload
)
await self.send_message(error_message)
# Boot notification
async def _send_boot_notification(self) -> None:
"""Send boot notification to CSMS"""
try:
boot_notification = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.BootNotification,
payload={
"chargingStation": self.station_info,
"reason": "PowerUp"
}
)
response = await self.send_message(boot_notification)
if response and response.get("status") == "Accepted":
self.is_authenticated = True
self.logger.info("Boot notification accepted by CSMS")
# Start heartbeat
asyncio.create_task(self._heartbeat_loop())
else:
self.logger.error("Boot notification rejected by CSMS")
raise OCPPAuthenticationError("Boot notification rejected")
except Exception as e:
self.logger.error(f"Error sending boot notification: {str(e)}")
raise OCPPInternalError(f"Failed to send boot notification: {str(e)}")
# Heartbeat
async def _heartbeat_loop(self) -> None:
"""Send periodic heartbeat to CSMS"""
while self.is_connected:
try:
await asyncio.sleep(self.settings.cp.heartbeat_interval)
if self.is_connected:
heartbeat = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.Heartbeat,
payload={}
)
await self.send_message(heartbeat)
self.last_heartbeat = datetime.now()
except Exception as e:
self.logger.error(f"Error sending heartbeat: {str(e)}")
break
# Status notification
async def send_status_notification(self, evse_id: int, connector_id: int,
status: str, timestamp: Optional[datetime] = None) -> None:
"""
Send status notification to CSMS
Args:
evse_id: EVSE ID
connector_id: Connector ID
status: Connector status
timestamp: Status timestamp
"""
try:
status_notification = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.StatusNotification,
payload={
"evseId": evse_id,
"connectorId": connector_id,
"status": status,
"timestamp": (timestamp or datetime.now()).isoformat()
}
)
await self.send_message(status_notification)
# Update local state
connector_key = f"{evse_id}_{connector_id}"
self.connectors[connector_key] = {
"evse_id": evse_id,
"connector_id": connector_id,
"status": status,
"timestamp": timestamp or datetime.now()
}
self.logger.info(f"Status notification sent: EVSE {evse_id}, Connector {connector_id}, Status {status}")
except Exception as e:
self.logger.error(f"Error sending status notification: {str(e)}")
raise OCPPInternalError(f"Failed to send status notification: {str(e)}")
# Transaction event
async def send_transaction_event(self, event_type: str, timestamp: datetime,
transaction_id: Optional[str] = None,
evse_id: Optional[int] = None,
connector_id: Optional[int] = None,
meter_value: Optional[List[Dict[str, Any]]] = None,
reason: Optional[str] = None,
custom_data: Optional[Dict[str, Any]] = None) -> None:
"""
Send transaction event to CSMS
Args:
event_type: Transaction event type
timestamp: Event timestamp
transaction_id: Transaction ID
evse_id: EVSE ID
connector_id: Connector ID
meter_value: Meter values
reason: Event reason
custom_data: Custom data
"""
try:
# Generate transaction ID if not provided
if not transaction_id and event_type == "Started":
self.transaction_counter += 1
transaction_id = f"TXN_{self.station_id}_{self.transaction_counter:06d}"
payload = {
"eventType": event_type,
"timestamp": timestamp.isoformat(),
"evseId": evse_id,
"connectorId": connector_id,
"customData": custom_data
}
if transaction_id:
payload["transactionId"] = transaction_id
if meter_value:
payload["meterValue"] = meter_value
if reason:
payload["reason"] = reason
transaction_event = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.TransactionEvent,
payload=payload
)
await self.send_message(transaction_event)
# Update local transaction state
if transaction_id:
if event_type == "Started":
self.active_transactions[transaction_id] = {
"transaction_id": transaction_id,
"evse_id": evse_id,
"connector_id": connector_id,
"start_time": timestamp,
"status": "Active"
}
elif event_type == "Ended":
if transaction_id in self.active_transactions:
transaction = self.active_transactions.pop(transaction_id)
transaction["end_time"] = timestamp
transaction["status"] = "Completed"
self.stats["total_transactions"] += 1
self.logger.log_transaction_event(
event=f"Transaction {event_type}",
transaction_id=transaction_id or "Unknown",
charging_station_id=self.station_id
)
except Exception as e:
self.logger.error(f"Error sending transaction event: {str(e)}")
raise OCPPInternalError(f"Failed to send transaction event: {str(e)}")
# Meter values
async def send_meter_values(self, evse_id: int, meter_value: List[Dict[str, Any]]) -> None:
"""
Send meter values to CSMS
Args:
evse_id: EVSE ID
meter_value: Meter values
"""
try:
meter_values = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.MeterValues,
payload={
"evseId": evse_id,
"meterValue": meter_value
}
)
await self.send_message(meter_values)
self.logger.info(f"Meter values sent for EVSE {evse_id}")
except Exception as e:
self.logger.error(f"Error sending meter values: {str(e)}")
raise OCPPInternalError(f"Failed to send meter values: {str(e)}")
# Data transfer
async def send_data_transfer(self, vendor_id: str, message_id: Optional[str] = None,
data: Optional[str] = None) -> Dict[str, Any]:
"""
Send data transfer to CSMS
Args:
vendor_id: Vendor ID
message_id: Message ID
data: Data to transfer
Returns:
Response from CSMS
"""
try:
payload = {
"vendorId": vendor_id
}
if message_id:
payload["messageId"] = message_id
if data:
payload["data"] = data
data_transfer = OCPPMessage(
message_type=MessageType.CALL,
unique_id=str(uuid.uuid4()),
action=ActionType.DataTransfer,
payload=payload
)
response = await self.send_message(data_transfer)
return response or {}
except Exception as e:
self.logger.error(f"Error sending data transfer: {str(e)}")
raise OCPPInternalError(f"Failed to send data transfer: {str(e)}")
# Request handlers (simplified implementations)
async def _handle_authorize(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle Authorize request"""
import uuid
# Generate RFID token with format RFID-{UUID(8)}
rfid_token = f"RFID-{str(uuid.uuid4())[:8].upper()}"
self.logger.info(f"Authorize request received, generated RFID token: {rfid_token}")
return {
"idTokenInfo": {
"status": "Accepted",
"idToken": rfid_token, # Include the generated RFID token
"cacheExpiryDateTime": (datetime.now() + timedelta(hours=1)).isoformat(),
"chargingPriority": 1,
"language1": "en",
"evseId": [1] # Available on all EVSEs
}
}
async def _handle_request_start_transaction(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle RequestStartTransaction request"""
# Simplified implementation - always accept
return {
"status": "Accepted",
"transactionId": f"TXN_{self.station_id}_{self.transaction_counter + 1:06d}"
}
async def _handle_request_stop_transaction(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle RequestStopTransaction request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_set_charging_profile(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetChargingProfile request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_clear_charging_profile(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ClearChargingProfile request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_charging_profiles(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetChargingProfiles request"""
# Simplified implementation - return empty list
return {
"chargingProfile": []
}
async def _handle_change_availability(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ChangeAvailability request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_unlock_connector(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle UnlockConnector request"""
# Simplified implementation - always accept
return {
"status": "Unlocked"
}
async def _handle_reset(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle Reset request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_clear_cache(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ClearCache request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_update_firmware(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle UpdateFirmware request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_send_local_list(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SendLocalList request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_local_list_version(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetLocalListVersion request"""
# Simplified implementation - return version 0
return {
"versionNumber": 0
}
async def _handle_reserve_now(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ReserveNow request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_cancel_reservation(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle CancelReservation request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_security_event_notification(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SecurityEventNotification request"""
# Simplified implementation - always accept
return {}
async def _handle_sign_certificate(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SignCertificate request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_certificate_signed(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle CertificateSigned request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_installed_certificate_ids(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetInstalledCertificateIds request"""
# Simplified implementation - return empty list
return {
"certificateHashData": []
}
async def _handle_delete_certificate(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle DeleteCertificate request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_install_certificate(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle InstallCertificate request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_certificate_status(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetCertificateStatus request"""
# Simplified implementation - return accepted
return {
"status": "Accepted"
}
async def _handle_get_certificate_chain_status(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetCertificateChainStatus request"""
# Simplified implementation - return accepted
return {
"status": "Accepted"
}
async def _handle_get_tariffs(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetTariffs request"""
# Simplified implementation - return empty list
return {
"tariff": []
}
async def _handle_set_default_tariff(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetDefaultTariff request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_clear_tariffs(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ClearTariffs request"""
# Simplified implementation - always accept
return {
"clearTariffsResult": []
}
async def _handle_set_display_message(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetDisplayMessage request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_display_messages(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetDisplayMessages request"""
# Simplified implementation - return empty list
return {
"messageInfo": []
}
async def _handle_clear_display_message(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ClearDisplayMessage request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_set_variable_monitoring(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetVariableMonitoring request"""
# Simplified implementation - always accept
return {
"setMonitoringResult": []
}
async def _handle_clear_variable_monitoring(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle ClearVariableMonitoring request"""
# Simplified implementation - always accept
return {
"clearMonitoringResult": []
}
async def _handle_set_monitoring_base(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetMonitoringBase request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_set_monitoring_level(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle SetMonitoringLevel request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_monitoring_report(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetMonitoringReport request"""
# Simplified implementation - return empty report
return {
"monitor": []
}
async def _handle_get_report(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetReport request"""
# Simplified implementation - return empty report
return {
"reportData": []
}
async def _handle_get_base_report(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetBaseReport request"""
# Simplified implementation - return empty report
return {
"reportData": []
}
async def _handle_trigger_message(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle TriggerMessage request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_data_transfer(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle DataTransfer request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_log(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle GetLog request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
async def _handle_get_15118_ev_certificate(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Handle Get15118EVCertificate request"""
# Simplified implementation - always accept
return {
"status": "Accepted"
}
def get_stats(self) -> Dict[str, Any]:
"""
Get client statistics
Returns:
Client statistics
"""
return self.stats.copy()
# Example usage
async def main():
"""Main function to run the CP client"""
client = CPClient()
try:
await client.connect()
# Keep client running
while client.is_connected:
await asyncio.sleep(1)
except KeyboardInterrupt:
print("Shutting down CP client...")
finally:
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
Articoli correlati
ocpp
python
Aggiornato 2026-02-03
central_system.py
central_system.py — python source code from the ocpp learning materials (ocpp/homework/central_system.py).
Leggi l'articolo →
ocpp
python
Aggiornato 2026-02-03
charge_point.py
charge_point.py — python source code from the ocpp learning materials (ocpp/homework/ocpp/charge_point.py).
Leggi l'articolo →
ocpp
python
Aggiornato 2026-02-03
exceptions.py
exceptions.py — python source code from the ocpp learning materials (ocpp/homework/ocpp/exceptions.py).
Leggi l'articolo →
ocpp
python
Aggiornato 2026-02-03
messages.py
messages.py — python source code from the ocpp learning materials (ocpp/homework/ocpp/messages.py).
Leggi l'articolo →
ocpp
python
Aggiornato 2026-02-03
routing.py
routing.py — python source code from the ocpp learning materials (ocpp/homework/ocpp/routing.py).
Leggi l'articolo →
ocpp
python
Aggiornato 2026-02-03
__init__.py
__init__.py — python source code from the ocpp learning materials (ocpp/homework/ocpp/v16/__init__.py).
Leggi l'articolo →