From 6be51ecaaca81c2bbb003d83dc2cd716ad42a41c Mon Sep 17 00:00:00 2001 From: "Dennis Lambe Jr." Date: Fri, 5 Jan 2024 10:12:24 -0500 Subject: [PATCH 01/27] v201:call,call_result,datatypes: complete and corrected type annotations --- ocpp/v201/call.py | 146 ++++++++++++++++---------------- ocpp/v201/call_result.py | 176 ++++++++++++++++++++------------------- ocpp/v201/datatypes.py | 2 +- 3 files changed, 164 insertions(+), 160 deletions(-) diff --git a/ocpp/v201/call.py b/ocpp/v201/call.py index ddc681606..34218d9b9 100644 --- a/ocpp/v201/call.py +++ b/ocpp/v201/call.py @@ -2,19 +2,21 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional +from ocpp.v201 import enums +from ocpp.v201 import datatypes @dataclass class Authorize: - id_token: Dict + id_token: datatypes.IdTokenType certificate: Optional[str] = None - iso15118_certificate_hash_data: Optional[List] = None + iso15118_certificate_hash_data: Optional[List[datatypes.OCSPRequestDataType]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class BootNotification: - charging_station: Dict - reason: str + charging_station: datatypes.ChargingStationType + reason: enums.BootReasonType custom_data: Optional[Dict[str, Any]] = None @@ -27,14 +29,14 @@ class CancelReservation: @dataclass class CertificateSigned: certificate_chain: str - certificate_type: Optional[str] = None + certificate_type: Optional[enums.CertificateSigningUseType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - operational_status: str - evse: Optional[Dict] = None + operational_status: enums.OperationalStatusType + evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None @@ -46,7 +48,7 @@ class ClearCache: @dataclass class ClearChargingProfile: charging_profile_id: Optional[int] = None - charging_profile_criteria: Optional[Dict] = None + charging_profile_criteria: Optional[datatypes.ClearChargingProfileType] = None custom_data: Optional[Dict[str, Any]] = None @@ -58,13 +60,13 @@ class ClearDisplayMessage: @dataclass class ClearVariableMonitoring: - id: List + id: List[int] custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearedChargingLimit: - charging_limit_source: str + charging_limit_source: enums.ChargingLimitSourceType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -81,8 +83,8 @@ class CustomerInformation: request_id: int report: bool clear: bool - customer_certificate: Optional[Dict] = None - id_token: Optional[Dict] = None + customer_certificate: Optional[datatypes.CertificateHashDataType] = None + id_token: Optional[datatypes.IdTokenType] = None customer_identifier: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @@ -97,13 +99,13 @@ class DataTransfer: @dataclass class DeleteCertificate: - certificate_hash_data: Dict + certificate_hash_data: datatypes.CertificateHashDataType custom_data: Optional[Dict[str, Any]] = None @dataclass class FirmwareStatusNotification: - status: str + status: enums.FirmwareStatusType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -111,7 +113,7 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: iso15118_schema_version: str - action: str + action: enums.CertificateActionType exi_request: str custom_data: Optional[Dict[str, Any]] = None @@ -119,20 +121,20 @@ class Get15118EVCertificate: @dataclass class GetBaseReport: request_id: int - report_base: str + report_base: enums.ReportBaseType custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCertificateStatus: - ocsp_request_data: Dict + ocsp_request_data: datatypes.OCSPRequestDataType custom_data: Optional[Dict[str, Any]] = None @dataclass class GetChargingProfiles: request_id: int - charging_profile: Dict + charging_profile: datatypes.ChargingProfileCriterionType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -141,22 +143,22 @@ class GetChargingProfiles: class GetCompositeSchedule: duration: int evse_id: int - charging_rate_unit: Optional[str] = None + charging_rate_unit: Optional[enums.ChargingRateUnitType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetDisplayMessages: request_id: int - id: Optional[List] = None - priority: Optional[str] = None - state: Optional[str] = None + id: Optional[List[int]] = None + priority: Optional[enums.MessagePriorityType] = None + state: Optional[enums.MessageStateType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - certificate_type: Optional[List] = None + certificate_type: Optional[List[enums.GetCertificateIdUseType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -167,8 +169,8 @@ class GetLocalListVersion: @dataclass class GetLog: - log: Dict - log_type: str + log: datatypes.LogParametersType + log_type: enums.LogType request_id: int retries: Optional[int] = None retry_interval: Optional[int] = None @@ -178,16 +180,16 @@ class GetLog: @dataclass class GetMonitoringReport: request_id: int - component_variable: Optional[List] = None - monitoring_criteria: Optional[List] = None + component_variable: Optional[List[datatypes.ComponentVariableType]] = None + monitoring_criteria: Optional[List[enums.MonitoringCriterionType]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetReport: request_id: int - component_variable: Optional[List] = None - component_criteria: Optional[List] = None + component_variable: Optional[List[datatypes.ComponentVariableType]] = None + component_criteria: Optional[List[enums.ComponentCriterionType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -199,7 +201,7 @@ class GetTransactionStatus: @dataclass class GetVariables: - get_variable_data: List + get_variable_data: List[datatypes.GetVariableDataType] custom_data: Optional[Dict[str, Any]] = None @@ -210,14 +212,14 @@ class Heartbeat: @dataclass class InstallCertificate: - certificate_type: str + certificate_type: enums.InstallCertificateUseType certificate: str custom_data: Optional[Dict[str, Any]] = None @dataclass class LogStatusNotification: - status: str + status: enums.UploadLogStatusType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -225,14 +227,14 @@ class LogStatusNotification: @dataclass class MeterValues: evse_id: int - meter_value: List + meter_value: List[datatypes.MeterValueType] custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyChargingLimit: - charging_limit: Dict - charging_schedule: Optional[List] = None + charging_limit: datatypes.ChargingLimitType + charging_schedule: Optional[List[datatypes.ChargingScheduleType]] = None evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -250,14 +252,14 @@ class NotifyCustomerInformation: @dataclass class NotifyDisplayMessages: request_id: int - message_info: Optional[List] = None + message_info: Optional[List[datatypes.MessageInfoType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyEVChargingNeeds: - charging_needs: Dict + charging_needs: datatypes.ChargingNeedsType evse_id: int max_schedule_tuples: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -266,7 +268,7 @@ class NotifyEVChargingNeeds: @dataclass class NotifyEVChargingSchedule: time_base: str - charging_schedule: Dict + charging_schedule: datatypes.ChargingScheduleType evse_id: int custom_data: Optional[Dict[str, Any]] = None @@ -275,7 +277,7 @@ class NotifyEVChargingSchedule: class NotifyEvent: generated_at: str seq_no: int - event_data: List + event_data: List[datatypes.EventDataType] tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -285,7 +287,7 @@ class NotifyMonitoringReport: request_id: int seq_no: int generated_at: str - monitor: Optional[List] = None + monitor: Optional[List[datatypes.MonitoringDataType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -295,7 +297,7 @@ class NotifyReport: request_id: int generated_at: str seq_no: int - report_data: Optional[List] = None + report_data: Optional[List[datatypes.ReportDataType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -312,8 +314,8 @@ class PublishFirmware: @dataclass class PublishFirmwareStatusNotification: - status: str - location: Optional[List] = None + status: enums.PublishFirmwareStatusType + location: Optional[List[str]] = None request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -321,8 +323,8 @@ class PublishFirmwareStatusNotification: @dataclass class ReportChargingProfiles: request_id: int - charging_limit_source: str - charging_profile: List + charging_limit_source: enums.ChargingLimitSourceType + charging_profile: List[datatypes.ChargingProfileType] evse_id: int tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -330,11 +332,11 @@ class ReportChargingProfiles: @dataclass class RequestStartTransaction: - id_token: Dict + id_token: datatypes.IdTokenType remote_start_id: int evse_id: Optional[int] = None - group_id_token: Optional[Dict] = None - charging_profile: Optional[Dict] = None + group_id_token: Optional[datatypes.IdTokenType] = None + charging_profile: Optional[datatypes.ChargingProfileType] = None custom_data: Optional[Dict[str, Any]] = None @@ -347,7 +349,7 @@ class RequestStopTransaction: @dataclass class ReservationStatusUpdate: reservation_id: int - reservation_update_status: str + reservation_update_status: enums.ReservationUpdateStatusType custom_data: Optional[Dict[str, Any]] = None @@ -355,16 +357,16 @@ class ReservationStatusUpdate: class ReserveNow: id: int expiry_date_time: str - id_token: Dict - connector_type: Optional[str] = None + id_token: datatypes.IdTokenType + connector_type: Optional[enums.ConnectorType] = None evse_id: Optional[int] = None - group_id_token: Optional[Dict] = None + group_id_token: Optional[datatypes.IdTokenType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class Reset: - type: str + type: enums.ResetType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -380,27 +382,27 @@ class SecurityEventNotification: @dataclass class SendLocalList: version_number: int - update_type: str - local_authorization_list: Optional[List] = None + update_type: enums.UpdateType + local_authorization_list: Optional[List[datatypes.AuthorizationData]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetChargingProfile: evse_id: int - charging_profile: Dict + charging_profile: datatypes.ChargingProfileType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetDisplayMessage: - message: Dict + message: datatypes.MessageInfoType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringBase: - monitoring_base: str + monitoring_base: enums.MonitorBaseType custom_data: Optional[Dict[str, Any]] = None @@ -413,33 +415,33 @@ class SetMonitoringLevel: @dataclass class SetNetworkProfile: configuration_slot: int - connection_data: Dict + connection_data: datatypes.NetworkConnectionProfileType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariableMonitoring: - set_monitoring_data: List + set_monitoring_data: List[datatypes.SetMonitoringDataType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariables: - set_variable_data: List + set_variable_data: List[datatypes.SetVariableDataType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SignCertificate: csr: str - certificate_type: Optional[str] = None + certificate_type: Optional[enums.CertificateSigningUseType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class StatusNotification: timestamp: str - connector_status: str + connector_status: enums.ConnectorStatusType evse_id: int connector_id: int custom_data: Optional[Dict[str, Any]] = None @@ -447,25 +449,25 @@ class StatusNotification: @dataclass class TransactionEvent: - event_type: str + event_type: enums.TransactionEventType timestamp: str - trigger_reason: str + trigger_reason: enums.TriggerReasonType seq_no: int - transaction_info: Dict - meter_value: Optional[List] = None + transaction_info: datatypes.TransactionType + meter_value: Optional[List[datatypes.MeterValueType]] = None offline: Optional[bool] = None number_of_phases_used: Optional[int] = None cable_max_current: Optional[int] = None reservation_id: Optional[int] = None - evse: Optional[Dict] = None - id_token: Optional[Dict] = None + evse: Optional[datatypes.EVSEType] = None + id_token: Optional[datatypes.IdTokenType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class TriggerMessage: - requested_message: str - evse: Optional[Dict] = None + requested_message: enums.MessageTriggerType + evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None @@ -485,7 +487,7 @@ class UnpublishFirmware: @dataclass class UpdateFirmware: request_id: int - firmware: Dict + firmware: datatypes.FirmwareType retries: Optional[int] = None retry_interval: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index 9bf387b26..d9aeeed3b 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -2,11 +2,13 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional +from ocpp.v201 import enums +from ocpp.v201 import datatypes @dataclass class Authorize: - id_token_info: Dict - certificate_status: Optional[str] = None + id_token_info: datatypes.IdTokenInfoType + certificate_status: Optional[enums.AuthorizeCertificateStatusType] = None custom_data: Optional[Dict[str, Any]] = None @@ -14,56 +16,56 @@ class Authorize: class BootNotification: current_time: str interval: int - status: str - status_info: Optional[Dict] = None + status: enums.RegistrationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CancelReservation: - status: str - status_info: Optional[Dict] = None + status: enums.CancelReservationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CertificateSigned: - status: str - status_info: Optional[Dict] = None + status: enums.CertificateSignedStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - status: str - status_info: Optional[Dict] = None + status: enums.ChangeAvailabilityStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearCache: - status: str - status_info: Optional[Dict] = None + status: enums.ClearCacheStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearChargingProfile: - status: str - status_info: Optional[Dict] = None + status: enums.ClearChargingProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearDisplayMessage: - status: str - status_info: Optional[Dict] = None + status: enums.ClearMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearVariableMonitoring: - clear_monitoring_result: List + clear_monitoring_result: List[enums.ClearMonitoringStatusType] custom_data: Optional[Dict[str, Any]] = None @@ -79,23 +81,23 @@ class CostUpdated: @dataclass class CustomerInformation: - status: str - status_info: Optional[Dict] = None + status: enums.CustomerInformationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class DataTransfer: - status: str - status_info: Optional[Dict] = None + status: enums.DataTransferStatusType + status_info: Optional[datatypes.StatusInfoType] = None data: Optional[Any] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class DeleteCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.DeleteCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -106,54 +108,54 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: - status: str + status: enums.Iso15118EVCertificateStatusType exi_response: str - status_info: Optional[Dict] = None + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetBaseReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCertificateStatus: - status: str - status_info: Optional[Dict] = None + status: enums.GetCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None ocsp_result: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetChargingProfiles: - status: str - status_info: Optional[Dict] = None + status: enums.GetChargingProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCompositeSchedule: - status: str - status_info: Optional[Dict] = None - schedule: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None + schedule: Optional[datatypes.CompositeScheduleType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetDisplayMessages: - status: str - status_info: Optional[Dict] = None + status: enums.GetDisplayMessagesStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - status: str - status_info: Optional[Dict] = None - certificate_hash_data_chain: Optional[List] = None + status: enums.GetInstalledCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None + certificate_hash_data_chain: Optional[List[datatypes.CertificateHashDataChainType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -165,23 +167,23 @@ class GetLocalListVersion: @dataclass class GetLog: - status: str - status_info: Optional[Dict] = None + status: enums.LogStatusType + status_info: Optional[datatypes.StatusInfoType] = None filename: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetMonitoringReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -194,7 +196,7 @@ class GetTransactionStatus: @dataclass class GetVariables: - get_variable_result: List + get_variable_result: List[datatypes.GetVariableResultType] custom_data: Optional[Dict[str, Any]] = None @@ -206,8 +208,8 @@ class Heartbeat: @dataclass class InstallCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.InstallCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -238,15 +240,15 @@ class NotifyDisplayMessages: @dataclass class NotifyEVChargingNeeds: - status: str - status_info: Optional[Dict] = None + status: enums.NotifyEVChargingNeedsStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyEVChargingSchedule: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -267,8 +269,8 @@ class NotifyReport: @dataclass class PublishFirmware: - status: str - status_info: Optional[Dict] = None + status: enums.PublishFirmwareStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -284,16 +286,16 @@ class ReportChargingProfiles: @dataclass class RequestStartTransaction: - status: str - status_info: Optional[Dict] = None + status: enums.RequestStartStopStatusType + status_info: Optional[datatypes.StatusInfoType] = None transaction_id: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class RequestStopTransaction: - status: str - status_info: Optional[Dict] = None + status: enums.RequestStartStopStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -304,15 +306,15 @@ class ReservationStatusUpdate: @dataclass class ReserveNow: - status: str - status_info: Optional[Dict] = None + status: enums.ReserveNowStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class Reset: - status: str - status_info: Optional[Dict] = None + status: enums.ResetStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -323,62 +325,62 @@ class SecurityEventNotification: @dataclass class SendLocalList: - status: str - status_info: Optional[Dict] = None + status: enums.SendLocalListStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetChargingProfile: - status: str - status_info: Optional[Dict] = None + status: enums.ChargingProfileStatus + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetDisplayMessage: - status: str - status_info: Optional[Dict] = None + status: enums.DisplayMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringBase: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringLevel: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetNetworkProfile: - status: str - status_info: Optional[Dict] = None + status: enums.SetNetworkProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariableMonitoring: - set_monitoring_result: List + set_monitoring_result: List[datatypes.SetMonitoringResultType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariables: - set_variable_result: List + set_variable_result: List[datatypes.SetVariableResultType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SignCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -391,35 +393,35 @@ class StatusNotification: class TransactionEvent: total_cost: Optional[float] = None charging_priority: Optional[int] = None - id_token_info: Optional[Dict] = None - updated_personal_message: Optional[Dict] = None + id_token_info: Optional[datatypes.IdTokenInfoType] = None + updated_personal_message: Optional[datatypes.MessageContentType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class TriggerMessage: - status: str - status_info: Optional[Dict] = None + status: enums.TriggerMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnlockConnector: - status: str - status_info: Optional[Dict] = None + status: enums.UnlockStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnpublishFirmware: - status: str + status: enums.UnpublishFirmwareStatusType custom_data: Optional[Dict[str, Any]] = None @dataclass class UpdateFirmware: - status: str - status_info: Optional[Dict] = None + status: enums.FirmwareStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 1a63ba43f..cc03fc31b 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[str] = None + unit: Optional[enums.UnitOfMeasureType] = None multiplier: Optional[int] = None From f9d5fd02e4736beb2bf293fcfa8f7549c85ecc96 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Fri, 22 Nov 2024 08:06:49 -0500 Subject: [PATCH 02/27] fixing linting errors --- ocpp/v201/call.py | 4 ++-- ocpp/v201/call_result.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ocpp/v201/call.py b/ocpp/v201/call.py index 34218d9b9..0f60762b5 100644 --- a/ocpp/v201/call.py +++ b/ocpp/v201/call.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional -from ocpp.v201 import enums -from ocpp.v201 import datatypes +from ocpp.v201 import datatypes, enums + @dataclass class Authorize: diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index d9aeeed3b..006001715 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional -from ocpp.v201 import enums -from ocpp.v201 import datatypes +from ocpp.v201 import datatypes, enums + @dataclass class Authorize: @@ -155,7 +155,9 @@ class GetDisplayMessages: class GetInstalledCertificateIds: status: enums.GetInstalledCertificateStatusType status_info: Optional[datatypes.StatusInfoType] = None - certificate_hash_data_chain: Optional[List[datatypes.CertificateHashDataChainType]] = None + certificate_hash_data_chain: Optional[ + List[datatypes.CertificateHashDataChainType] + ] = None custom_data: Optional[Dict[str, Any]] = None From 68e048b99d0b0369e511ed8e4b374b13c04185a7 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Fri, 22 Nov 2024 09:01:15 -0500 Subject: [PATCH 03/27] Add code of conduct, contributing, security and support docs. Also includes a pull request template. Contributes to https://github.com/mobilityhouse/ocpp/issues/671 --- .github/pull_request_template.md | 21 +++++++++ CODE_OF_CONDUCT.md | 74 ++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 41 ++++++++++++++++++ SECURITY.md | 33 ++++++++++++++ SUPPORT.md | 34 +++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 SUPPORT.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..2e8477f4b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +### Changes included in this PR + +*(Bug fix, feature, docs update, ...)* + +### Current behavior + +*Link to an open issue here...* + +### New behavior + +*If this is a feature change, describe the new behavior* + +### Impact + +*Describe breaking changes, including changes a users might need to make due to this PR* + +### Checklist + +1. [ ] Does your submission pass the existing tests? +2. [ ] Are there new tests that cover these additions/changes? +3. [ ] Have you linted your code locally before submission? diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..86a391351 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at {{ email }}. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..b0037efe8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +## Contributing + +[fork]: /fork +[pr]: /compare +[style]: https://standardjs.com/ +[code-of-conduct]: CODE_OF_CONDUCT.md + +Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. + +Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. + +## Issues and PRs + +If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them. + +We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR. + +Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you. + +## Submitting a pull request + +1. [Fork][fork] and clone the repository. +1. Create a new branch: `git checkout -b my-branch-name`. +1. Configure and install the dependencies: `poetry install`. +1. Make sure the tests pass on your machine: `make install & make tests` +1. Make your change, add tests, and make sure the tests still pass. +1. Push to your fork and [submit a pull request][pr] and complete the information in the pull request template. + +## Linting requirements + +using `make install & make tests` will also run the following linters: + +- [Black: The uncompromising Python code formatter](https://black.readthedocs.io/en/stable/) +- [isort your imports, so you don't have to](https://pycqa.github.io/isort/) +- [flake8: Your Tool For Style Guide Enforcement](https://flake8.pycqa.org/en/latest/) + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) +- [GitHub Help](https://help.github.com) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..bd76a0f69 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,33 @@ +# Security Policy + +This document outlines security procedures and general policies for this OCPP project. + +## Supported Versions + +The currently supported versions of this OCPP project are: + +| Version | Supported | +|----------| ------------------ | +| 2.0.0 | :white_check_mark: | +| 0.26.0 | :white_check_mark: | +| < 0.26.0 | :x: | + +## Reporting a Vulnerability + +Please include the requested information listed below (as much as you can provide) to help +us better understand the nature and scope of the possible issue: + +- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) +- Full paths of source file(s) related to the manifestation of the issue +- The location of the affected source code (tag/branch/commit or direct URL) +- Any special configuration required to reproduce the issue +- Step-by-step instructions to reproduce the issue +- Proof-of-concept or exploit code (if possible) +- Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. Thanks! diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..72b64a6c6 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,34 @@ +# Support + +This article explains where to get help with this OCPP project. +Please read through the following guidelines. + +> 👉 **Note**: before participating in our community, please read our +> [code of conduct][coc]. +> By interacting with this repository, organization, or community you agree to +> abide by its terms. + +## Asking quality questions + +Questions can go to [GitHub discussions][chat]. + +Help us help you! +Spend time framing questions and add links and resources. +Spending the extra time up front can help save everyone time in the long run. +Here are some tips: + +* Search to find out if a similar question has been asked or a similar issue has been reported +* Check to see if a PR is already in progress for the issue you want to raise +* Try to define what you need help with: + * Is there something in particular you want to do? + * What problem are you encountering and what steps have you taken to try + and fix it? + * Is there a concept you don’t understand? +* Provide sample code, such as a [CodeSandbox][cs] or video, if possible +* Screenshots can help, but if there’s important text such as code or error + messages in them, please also provide those as text +* The more time you put into asking your question, the better we can help you + +## Contributions + +See [`contributing.md`][contributing] on how to contribute. From c5057c44298af023cf0837a2f21397191969593f Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 21:22:22 -0500 Subject: [PATCH 04/27] adding unit tests for all the v201 data types to make sure they rehydrate the same as before. the enums and datatypes had an overlapping dataclass, both called UnitOfMeasureType. changed the enum to UnitOfMeasureUnitType. --- ocpp/v201/datatypes.py | 2 +- ocpp/v201/enums.py | 2 +- tests/v201/test_v201_data_types.py | 914 +++++++++++++++++++++++++++++ 3 files changed, 916 insertions(+), 2 deletions(-) create mode 100644 tests/v201/test_v201_data_types.py diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index cc03fc31b..27bb43af0 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.UnitOfMeasureType] = None + unit: Optional[enums.UnitOfMeasureUnitType] = None multiplier: Optional[int] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2f903ca75..2c69e953b 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureType(StrEnum): +class UnitOfMeasureUnitType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py new file mode 100644 index 000000000..570c8e186 --- /dev/null +++ b/tests/v201/test_v201_data_types.py @@ -0,0 +1,914 @@ +import json +from dataclasses import asdict +from typing import TypeVar + +from ocpp.v201.datatypes import * +from ocpp.v201.enums import ( + APNAuthenticationType, AttributeType, ChargingProfileKindType, + ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, + EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, + MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, + OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, + ReasonType, SetMonitoringStatusType, SetVariableStatusType, + UnitOfMeasureUnitType, VPNType +) + +T = TypeVar('T', bound='dataclass') + + +def to_datatype(cls, dc: T): + to_dict = asdict(dc) + to_json = json.dumps(to_dict) + from_json = json.loads(to_json) + return cls(**from_json) + + +def test_ac_charging_parameters_type(): + acpt = ACChargingParametersType( + energy_amount=20.5, + ev_min_current=10.0, + ev_max_current=32.0, + ev_max_voltage=400 + ) + + new_acpt = to_datatype(ACChargingParametersType, acpt) + + assert new_acpt.energy_amount == acpt.energy_amount + assert new_acpt.ev_min_current == acpt.ev_min_current + assert new_acpt.ev_max_current == acpt.ev_max_current + assert new_acpt.ev_max_voltage == acpt.ev_max_voltage + + +def test_additional_info_type(): + ait = AdditionalInfoType( + additional_id_token="additional_token123", + type="type_value" + ) + + new_ait = to_datatype(AdditionalInfoType, ait) + + assert new_ait.additional_id_token == ait.additional_id_token + assert new_ait.type == ait.type + + +def test_apn_type(): + at = APNType( + apn="internet.example.com", + apn_authentication="AUTO", + apn_user_name="username", + apn_password="password", + sim_pin=1234, + preferred_network="preferred", + use_only_preferred_network=True + ) + + new_at = to_datatype(APNType, at) + + assert new_at.apn == at.apn + assert new_at.apn_authentication == at.apn_authentication + assert new_at.apn_user_name == at.apn_user_name + assert new_at.apn_password == at.apn_password + assert new_at.sim_pin == at.sim_pin + assert new_at.preferred_network == at.preferred_network + assert new_at.use_only_preferred_network == at.use_only_preferred_network + + +def test_authorization_data(): + ad = AuthorizationData( + id_token_info=IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr" + ), + id_token=IdTokenType.iso14443 + ) + + new_ad = to_datatype(AuthorizationData, ad) + + assert isinstance(new_ad.id_token_info, dict) + assert new_ad.id_token_info['status'] == ad.id_token_info.status + assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time + assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority + assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 + assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert isinstance(new_ad.id_token, str) + assert new_ad.id_token == ad.id_token + + +def test_certificate_hash_data_chain_type(): + chdct = CertificateHashDataChainType( + certificate_type="V2G", + certificate_hash_data=CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ), + child_certificate_hash_data=[ + CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="child_issuer_hash", + issuer_key_hash="child_key_hash", + serial_number="child_serial123" + ) + ] + ) + + new_chdct = to_datatype(CertificateHashDataChainType, chdct) + + assert new_chdct.certificate_type == chdct.certificate_type + assert isinstance(new_chdct.certificate_hash_data, dict) + assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm + assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash + assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash + assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert isinstance(new_chdct.child_certificate_hash_data[0], dict) + assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + + +def test_certificate_hash_data_type(): + chdt = CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ) + + new_chdt = to_datatype(CertificateHashDataType, chdt) + + assert new_chdt.hash_algorithm == chdt.hash_algorithm + assert new_chdt.issuer_name_hash == chdt.issuer_name_hash + assert new_chdt.issuer_key_hash == chdt.issuer_key_hash + assert new_chdt.serial_number == chdt.serial_number + + +def test_charging_limit_type(): + clt = ChargingLimitType( + charging_limit_source="EMS", + is_grid_critical=True + ) + + new_clt = to_datatype(ChargingLimitType, clt) + + assert new_clt.charging_limit_source == clt.charging_limit_source + assert new_clt.is_grid_critical == clt.is_grid_critical + + +def test_charging_needs_type(): + cnt = ChargingNeedsType( + requested_energy_transfer=EnergyTransferModeType.dc, + departure_time="2024-01-01T10:00:00Z", + ac_charging_parameters=ACChargingParametersType( + energy_amount=20, + ev_min_current=10, + ev_max_current=32, + ev_max_voltage=400 + ), + dc_charging_parameters=DCChargingParametersType( + ev_max_current=100, + ev_max_voltage=500, + energy_amount=50, + ev_max_power=50000, + state_of_charge=80 + ) + ) + + new_cnt = to_datatype(ChargingNeedsType, cnt) + + assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer + assert new_cnt.departure_time == cnt.departure_time + assert isinstance(new_cnt.ac_charging_parameters, dict) + assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount + assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert isinstance(new_cnt.dc_charging_parameters, dict) + assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current + assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + + +def test_charging_profile_criterion_type(): + cpct = ChargingProfileCriterionType( + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0, + charging_profile_id=[1, 2, 3] + ) + + new_cpct = to_datatype(ChargingProfileCriterionType, cpct) + + assert new_cpct.charging_profile_purpose == cpct.charging_profile_purpose + assert new_cpct.stack_level == cpct.stack_level + assert new_cpct.charging_profile_id == cpct.charging_profile_id + + +def test_charging_profile_type(): + cpt = ChargingProfileType( + id=1, + stack_level=0, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + charging_profile_kind=ChargingProfileKindType.absolute, + charging_schedule=[ + ChargingScheduleType( + id=1, + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ], + start_schedule="2024-01-01T10:00:00Z", + duration=3600 + ) + ], + valid_from="2024-01-01T00:00:00Z", + valid_to="2024-12-31T23:59:59Z" + ) + + new_cpt = to_datatype(ChargingProfileType, cpt) + + assert new_cpt.id == cpt.id + assert new_cpt.stack_level == cpt.stack_level + assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose + assert new_cpt.charging_profile_kind == cpt.charging_profile_kind + assert isinstance(new_cpt.charging_schedule[0], dict) + assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.valid_from == cpt.valid_from + assert new_cpt.valid_to == cpt.valid_to + + +def test_charging_schedule_period_type(): + cspt = ChargingSchedulePeriodType( + start_period=0, + limit=32.0, + number_phases=3, + phase_to_use=1 + ) + + new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) + + assert new_cspt.start_period == cspt.start_period + assert new_cspt.limit == cspt.limit + assert new_cspt.number_phases == cspt.number_phases + assert new_cspt.phase_to_use == cspt.phase_to_use + + +def test_charging_station_type(): + cst = ChargingStationType( + model="Station Model X", + vendor_name="Vendor ABC", + serial_number="SN123456", + modem=ModemType( + iccid="89001234567890123456", + imsi="123456789012345" + ), + firmware_version="1.2.3" + ) + + new_cst = to_datatype(ChargingStationType, cst) + + assert new_cst.model == cst.model + assert new_cst.vendor_name == cst.vendor_name + assert new_cst.serial_number == cst.serial_number + assert isinstance(new_cst.modem, dict) + assert new_cst.modem['iccid'] == cst.modem.iccid + assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.firmware_version == cst.firmware_version + + +def test_clear_charging_profile_type(): + ccpt = ClearChargingProfileType( + evse_id=1, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0 + ) + + new_ccpt = to_datatype(ClearChargingProfileType, ccpt) + + assert new_ccpt.evse_id == ccpt.evse_id + assert new_ccpt.charging_profile_purpose == ccpt.charging_profile_purpose + assert new_ccpt.stack_level == ccpt.stack_level + + +def test_clear_monitoring_result_type(): + cmrt = ClearMonitoringResultType( + status="Accepted", + id=123, + status_info=StatusInfoType( + reason_code="Cleared", + additional_info="Successfully cleared monitoring" + ) + ) + + new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) + + assert new_cmrt.status == cmrt.status + assert new_cmrt.id == cmrt.id + assert isinstance(new_cmrt.status_info, dict) + assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code + assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + + +def test_component_type(): + ct = ComponentType( + name="MainController", + instance="instance1", + evse=EVSEType( + id=1, + connector_id=2 + ) + ) + + new_ct = to_datatype(ComponentType, ct) + + assert new_ct.name == ct.name + assert new_ct.instance == ct.instance + assert isinstance(new_ct.evse, dict) + assert new_ct.evse['id'] == ct.evse.id + assert new_ct.evse['connector_id'] == ct.evse.connector_id + + +def test_component_variable_type(): + cvt = ComponentVariableType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_cvt = to_datatype(ComponentVariableType, cvt) + + assert isinstance(new_cvt.component, dict) + assert new_cvt.component['name'] == cvt.component.name + assert new_cvt.component['instance'] == cvt.component.instance + assert isinstance(new_cvt.variable, dict) + assert new_cvt.variable['name'] == cvt.variable.name + assert new_cvt.variable['instance'] == cvt.variable.instance + + +def test_composite_schedule_type(): + cst = CompositeScheduleType( + evse_id=1, + duration=3600, + schedule_start="2024-01-01T10:00:00Z", + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ] + ) + + new_cst = to_datatype(CompositeScheduleType, cst) + + assert new_cst.evse_id == cst.evse_id + assert new_cst.duration == cst.duration + assert new_cst.schedule_start == cst.schedule_start + assert new_cst.charging_rate_unit == cst.charging_rate_unit + assert isinstance(new_cst.charging_schedule_period[0], dict) + assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period + assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + + +def test_consumption_cost_type(): + cct = ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + + new_cct = to_datatype(ConsumptionCostType, cct) + + assert new_cct.start_value == cct.start_value + assert isinstance(new_cct.cost[0], dict) + assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind + assert new_cct.cost[0]['amount'] == cct.cost[0].amount + assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + + +def test_cost_type(): + ct = CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + + new_ct = to_datatype(CostType, ct) + + assert new_ct.cost_kind == ct.cost_kind + assert new_ct.amount == ct.amount + assert new_ct.amount_multiplier == ct.amount_multiplier + + +def test_event_data_type(): + edt = EventDataType( + event_id=1, + timestamp="2024-01-01T10:00:00Z", + trigger="Alerting", + actual_value="High Temperature", + tech_code="TC001", + tech_info="Temperature sensor reading high", + cleared=False, + transaction_id="TX001", + variable_monitoring_id=1, + event_notification_type="HardWiredNotification", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ) + ) + + new_edt = to_datatype(EventDataType, edt) + + assert new_edt.event_id == edt.event_id + assert new_edt.timestamp == edt.timestamp + assert new_edt.trigger == edt.trigger + assert new_edt.actual_value == edt.actual_value + assert new_edt.tech_code == edt.tech_code + assert new_edt.tech_info == edt.tech_info + assert new_edt.cleared == edt.cleared + assert new_edt.transaction_id == edt.transaction_id + assert new_edt.variable_monitoring_id == edt.variable_monitoring_id + assert new_edt.event_notification_type == edt.event_notification_type + assert isinstance(new_edt.component, dict) + assert new_edt.component['name'] == edt.component.name + assert isinstance(new_edt.variable, dict) + assert new_edt.variable['name'] == edt.variable.name + + +def test_firmware_type(): + ft = FirmwareType( + location="https://firmware.example.com/v1.2.3", + retrieve_date_time="2024-01-01T10:00:00Z", + install_date_time="2024-01-01T11:00:00Z", + signing_certificate="MIIB...", + signature="SHA256..." + ) + + new_ft = to_datatype(FirmwareType, ft) + + assert new_ft.location == ft.location + assert new_ft.retrieve_date_time == ft.retrieve_date_time + assert new_ft.install_date_time == ft.install_date_time + assert new_ft.signing_certificate == ft.signing_certificate + assert new_ft.signature == ft.signature + + +def test_get_variable_data_type(): + gvdt = GetVariableDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ), + attribute_type=AttributeType.actual + ) + + new_gvdt = to_datatype(GetVariableDataType, gvdt) + + assert isinstance(new_gvdt.component, dict) + assert new_gvdt.component['name'] == gvdt.component.name + assert new_gvdt.component['instance'] == gvdt.component.instance + assert isinstance(new_gvdt.variable, dict) + assert new_gvdt.variable['name'] == gvdt.variable.name + assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.attribute_type == gvdt.attribute_type + + +def test_get_variable_result_type(): + gvrt = GetVariableResultType( + attribute_status="Accepted", + attribute_type=AttributeType.actual, + attribute_value="100", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_gvrt = to_datatype(GetVariableResultType, gvrt) + + assert new_gvrt.attribute_status == gvrt.attribute_status + assert new_gvrt.attribute_type == gvrt.attribute_type + assert new_gvrt.attribute_value == gvrt.attribute_value + assert isinstance(new_gvrt.component, dict) + assert new_gvrt.component['name'] == gvrt.component.name + assert isinstance(new_gvrt.variable, dict) + assert new_gvrt.variable['name'] == gvrt.variable.name + + +def test_id_token_info_type(): + itit = IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr", + group_id_token=IdTokenType.central, + personal_message=MessageContentType( + format=MessageFormatType.ascii, + content="Welcome back!", + language="en" + ) + ) + + new_itit = to_datatype(IdTokenInfoType, itit) + + assert new_itit.status == itit.status + assert new_itit.cache_expiry_date_time == itit.cache_expiry_date_time + assert new_itit.charging_priority == itit.charging_priority + assert new_itit.language_1 == itit.language_1 + assert new_itit.language_2 == itit.language_2 + assert isinstance(new_itit.group_id_token, str) + assert new_itit.group_id_token == itit.group_id_token + assert isinstance(new_itit.personal_message, dict) + assert new_itit.personal_message['content'] == itit.personal_message.content + + +def test_log_parameters_type(): + lpt = LogParametersType( + remote_location="https://logs.example.com", + oldest_timestamp="2024-01-01T00:00:00Z", + latest_timestamp="2024-01-01T23:59:59Z" + ) + + new_lpt = to_datatype(LogParametersType, lpt) + + assert new_lpt.remote_location == lpt.remote_location + assert new_lpt.oldest_timestamp == lpt.oldest_timestamp + assert new_lpt.latest_timestamp == lpt.latest_timestamp + + +def test_message_info_type(): + mit = MessageInfoType( + id=1, + priority=1, + message=MessageContentType( + format=MessageFormatType.ascii, + content="Important notice", + language="en" + ), + display=ComponentType( + name="MainDisplay", + instance="instance1" + ), + state="Charging" + ) + + new_mit = to_datatype(MessageInfoType, mit) + + assert new_mit.id == mit.id + assert new_mit.priority == mit.priority + assert isinstance(new_mit.message, dict) + assert new_mit.message['content'] == mit.message.content + assert isinstance(new_mit.display, dict) + assert new_mit.display['name'] == mit.display.name + assert new_mit.state == mit.state + + +def test_meter_value_type(): + mvt = MeterValueType( + timestamp="2024-01-01T10:00:00Z", + sampled_value=[ + SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet + ) + ] + ) + + new_mvt = to_datatype(MeterValueType, mvt) + + assert new_mvt.timestamp == mvt.timestamp + assert isinstance(new_mvt.sampled_value[0], dict) + assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + + +def test_modem_type(): + mt = ModemType( + iccid="89012345678901234567", + imsi="123456789012345" + ) + + new_mt = to_datatype(ModemType, mt) + + assert new_mt.iccid == mt.iccid + assert new_mt.imsi == mt.imsi + + +def test_monitoring_data_type(): + mdt = MonitoringDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_monitoring=VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + ) + + new_mdt = to_datatype(MonitoringDataType, mdt) + + assert isinstance(new_mdt.component, dict) + assert new_mdt.component['name'] == mdt.component.name + assert isinstance(new_mdt.variable, dict) + assert new_mdt.variable['name'] == mdt.variable.name + assert isinstance(new_mdt.variable_monitoring, dict) + assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + + +def test_network_connection_profile_type(): + ncpt = NetworkConnectionProfileType( + ocpp_version=OCPPVersionType.ocpp20, + ocpp_transport=OCPPTransportType.json, + ocpp_csms_url="wss://example.com/ocpp", + message_timeout=30, + security_profile=1, + ocpp_interface=OCPPInterfaceType.wired0 + ) + + new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) + + assert new_ncpt.ocpp_version == ncpt.ocpp_version + assert new_ncpt.ocpp_transport == ncpt.ocpp_transport + assert new_ncpt.ocpp_csms_url == ncpt.ocpp_csms_url + assert new_ncpt.message_timeout == ncpt.message_timeout + assert new_ncpt.security_profile == ncpt.security_profile + assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + + +def test_ocsp_request_data_type(): + ordt = OCSPRequestDataType( + hash_algorithm=HashAlgorithmType.sha256, + issuer_name_hash="issuer_hash_value", + issuer_key_hash="issuer_key_hash_value", + serial_number="serial123", + responder_url="http://ocsp.example.com" + ) + + new_ordt = to_datatype(OCSPRequestDataType, ordt) + + assert new_ordt.hash_algorithm == ordt.hash_algorithm + assert new_ordt.issuer_name_hash == ordt.issuer_name_hash + assert new_ordt.issuer_key_hash == ordt.issuer_key_hash + assert new_ordt.serial_number == ordt.serial_number + assert new_ordt.responder_url == ordt.responder_url + + +def test_relative_time_interval_type(): + rtit = RelativeTimeIntervalType( + start=0, + duration=3600 + ) + + new_rtit = to_datatype(RelativeTimeIntervalType, rtit) + + assert new_rtit.start == rtit.start + assert new_rtit.duration == rtit.duration + + +def test_report_data_type(): + rdt = ReportDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_attribute=[ + VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + ], + variable_characteristics=VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + ) + + new_rdt = to_datatype(ReportDataType, rdt) + + assert isinstance(new_rdt.component, dict) + assert new_rdt.component['name'] == rdt.component.name + assert isinstance(new_rdt.variable, dict) + assert new_rdt.variable['name'] == rdt.variable.name + assert isinstance(new_rdt.variable_attribute[0], dict) + assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert isinstance(new_rdt.variable_characteristics, dict) + assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit + assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type + assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + + +def test_sales_tariff_entry_type(): + stet = SalesTariffEntryType( + e_price_level=1, + relative_time_interval=RelativeTimeIntervalType( + start=0, + duration=3600 + ), + consumption_cost=[ + ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + ] + ) + + new_stet = to_datatype(SalesTariffEntryType, stet) + + assert new_stet.e_price_level == stet.e_price_level + assert isinstance(new_stet.relative_time_interval, dict) + assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start + assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert isinstance(new_stet.consumption_cost[0], dict) + assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value + assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) + assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind + assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount + assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + + +def test_sampled_value_type(): + svt = SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet, + unit_of_measure=UnitOfMeasureType( + unit=UnitOfMeasureUnitType.v, + multiplier=0 + ) + ) + + new_svt = to_datatype(SampledValueType, svt) + + assert new_svt.value == svt.value + assert new_svt.context == svt.context + assert new_svt.measurand == svt.measurand + assert new_svt.phase == svt.phase + assert new_svt.location == svt.location + assert isinstance(new_svt.unit_of_measure, dict) + assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + + +def test_set_monitoring_data_type(): + smdt = SetMonitoringDataType( + value=100.0, + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + id=123456 + ) + + new_smdt = to_datatype(SetMonitoringDataType, smdt) + + assert new_smdt.value == smdt.value + assert new_smdt.type == smdt.type + assert new_smdt.severity == smdt.severity + assert isinstance(new_smdt.component, dict) + assert new_smdt.component['name'] == smdt.component.name + assert new_smdt.component['instance'] == smdt.component.instance + assert isinstance(new_smdt.variable, dict) + assert new_smdt.variable['name'] == smdt.variable.name + assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.id == smdt.id + + +def test_unit_of_measure_type(): + uomt = UnitOfMeasureType( + #unit=UnitOfMeasureType.w, + multiplier=1 + ) + + new_uomt = to_datatype(UnitOfMeasureType, uomt) + + assert new_uomt.unit == uomt.unit + assert new_uomt.multiplier == uomt.multiplier + + +def test_variable_attribute_type(): + vat = VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + + new_vat = to_datatype(VariableAttributeType, vat) + + assert new_vat.type == vat.type + assert new_vat.value == vat.value + assert new_vat.mutability == vat.mutability + assert new_vat.persistent == vat.persistent + assert new_vat.constant == vat.constant + + +def test_variable_characteristics_type(): + vct = VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + + new_vct = to_datatype(VariableCharacteristicsType, vct) + + assert new_vct.unit == vct.unit + assert new_vct.data_type == vct.data_type + assert new_vct.min_limit == vct.min_limit + assert new_vct.max_limit == vct.max_limit + assert new_vct.values_list == vct.values_list + assert new_vct.supports_monitoring == vct.supports_monitoring + + +def test_variable_monitoring_type(): + vmt = VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + + new_vmt = to_datatype(VariableMonitoringType, vmt) + + assert new_vmt.id == vmt.id + assert new_vmt.transaction == vmt.transaction + assert new_vmt.value == vmt.value + assert new_vmt.type == vmt.type + assert new_vmt.severity == vmt.severity + + + + + + From ef88e26e2f9a645a0a7dff191ae6a63929de9880 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 21:25:42 -0500 Subject: [PATCH 05/27] adding unit test to the non-nested dataclasses of v2.0.1 so that any changes made to nested dataclasses don't affect functionality --- ocpp/v201/enums.py | 2 +- tests/v201/test_v201_data_types.py | 914 +++++++++++++++++++++++++++++ 2 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 tests/v201/test_v201_data_types.py diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2f903ca75..2c69e953b 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureType(StrEnum): +class UnitOfMeasureUnitType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py new file mode 100644 index 000000000..570c8e186 --- /dev/null +++ b/tests/v201/test_v201_data_types.py @@ -0,0 +1,914 @@ +import json +from dataclasses import asdict +from typing import TypeVar + +from ocpp.v201.datatypes import * +from ocpp.v201.enums import ( + APNAuthenticationType, AttributeType, ChargingProfileKindType, + ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, + EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, + MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, + OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, + ReasonType, SetMonitoringStatusType, SetVariableStatusType, + UnitOfMeasureUnitType, VPNType +) + +T = TypeVar('T', bound='dataclass') + + +def to_datatype(cls, dc: T): + to_dict = asdict(dc) + to_json = json.dumps(to_dict) + from_json = json.loads(to_json) + return cls(**from_json) + + +def test_ac_charging_parameters_type(): + acpt = ACChargingParametersType( + energy_amount=20.5, + ev_min_current=10.0, + ev_max_current=32.0, + ev_max_voltage=400 + ) + + new_acpt = to_datatype(ACChargingParametersType, acpt) + + assert new_acpt.energy_amount == acpt.energy_amount + assert new_acpt.ev_min_current == acpt.ev_min_current + assert new_acpt.ev_max_current == acpt.ev_max_current + assert new_acpt.ev_max_voltage == acpt.ev_max_voltage + + +def test_additional_info_type(): + ait = AdditionalInfoType( + additional_id_token="additional_token123", + type="type_value" + ) + + new_ait = to_datatype(AdditionalInfoType, ait) + + assert new_ait.additional_id_token == ait.additional_id_token + assert new_ait.type == ait.type + + +def test_apn_type(): + at = APNType( + apn="internet.example.com", + apn_authentication="AUTO", + apn_user_name="username", + apn_password="password", + sim_pin=1234, + preferred_network="preferred", + use_only_preferred_network=True + ) + + new_at = to_datatype(APNType, at) + + assert new_at.apn == at.apn + assert new_at.apn_authentication == at.apn_authentication + assert new_at.apn_user_name == at.apn_user_name + assert new_at.apn_password == at.apn_password + assert new_at.sim_pin == at.sim_pin + assert new_at.preferred_network == at.preferred_network + assert new_at.use_only_preferred_network == at.use_only_preferred_network + + +def test_authorization_data(): + ad = AuthorizationData( + id_token_info=IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr" + ), + id_token=IdTokenType.iso14443 + ) + + new_ad = to_datatype(AuthorizationData, ad) + + assert isinstance(new_ad.id_token_info, dict) + assert new_ad.id_token_info['status'] == ad.id_token_info.status + assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time + assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority + assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 + assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert isinstance(new_ad.id_token, str) + assert new_ad.id_token == ad.id_token + + +def test_certificate_hash_data_chain_type(): + chdct = CertificateHashDataChainType( + certificate_type="V2G", + certificate_hash_data=CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ), + child_certificate_hash_data=[ + CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="child_issuer_hash", + issuer_key_hash="child_key_hash", + serial_number="child_serial123" + ) + ] + ) + + new_chdct = to_datatype(CertificateHashDataChainType, chdct) + + assert new_chdct.certificate_type == chdct.certificate_type + assert isinstance(new_chdct.certificate_hash_data, dict) + assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm + assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash + assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash + assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert isinstance(new_chdct.child_certificate_hash_data[0], dict) + assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + + +def test_certificate_hash_data_type(): + chdt = CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ) + + new_chdt = to_datatype(CertificateHashDataType, chdt) + + assert new_chdt.hash_algorithm == chdt.hash_algorithm + assert new_chdt.issuer_name_hash == chdt.issuer_name_hash + assert new_chdt.issuer_key_hash == chdt.issuer_key_hash + assert new_chdt.serial_number == chdt.serial_number + + +def test_charging_limit_type(): + clt = ChargingLimitType( + charging_limit_source="EMS", + is_grid_critical=True + ) + + new_clt = to_datatype(ChargingLimitType, clt) + + assert new_clt.charging_limit_source == clt.charging_limit_source + assert new_clt.is_grid_critical == clt.is_grid_critical + + +def test_charging_needs_type(): + cnt = ChargingNeedsType( + requested_energy_transfer=EnergyTransferModeType.dc, + departure_time="2024-01-01T10:00:00Z", + ac_charging_parameters=ACChargingParametersType( + energy_amount=20, + ev_min_current=10, + ev_max_current=32, + ev_max_voltage=400 + ), + dc_charging_parameters=DCChargingParametersType( + ev_max_current=100, + ev_max_voltage=500, + energy_amount=50, + ev_max_power=50000, + state_of_charge=80 + ) + ) + + new_cnt = to_datatype(ChargingNeedsType, cnt) + + assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer + assert new_cnt.departure_time == cnt.departure_time + assert isinstance(new_cnt.ac_charging_parameters, dict) + assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount + assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert isinstance(new_cnt.dc_charging_parameters, dict) + assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current + assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + + +def test_charging_profile_criterion_type(): + cpct = ChargingProfileCriterionType( + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0, + charging_profile_id=[1, 2, 3] + ) + + new_cpct = to_datatype(ChargingProfileCriterionType, cpct) + + assert new_cpct.charging_profile_purpose == cpct.charging_profile_purpose + assert new_cpct.stack_level == cpct.stack_level + assert new_cpct.charging_profile_id == cpct.charging_profile_id + + +def test_charging_profile_type(): + cpt = ChargingProfileType( + id=1, + stack_level=0, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + charging_profile_kind=ChargingProfileKindType.absolute, + charging_schedule=[ + ChargingScheduleType( + id=1, + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ], + start_schedule="2024-01-01T10:00:00Z", + duration=3600 + ) + ], + valid_from="2024-01-01T00:00:00Z", + valid_to="2024-12-31T23:59:59Z" + ) + + new_cpt = to_datatype(ChargingProfileType, cpt) + + assert new_cpt.id == cpt.id + assert new_cpt.stack_level == cpt.stack_level + assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose + assert new_cpt.charging_profile_kind == cpt.charging_profile_kind + assert isinstance(new_cpt.charging_schedule[0], dict) + assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.valid_from == cpt.valid_from + assert new_cpt.valid_to == cpt.valid_to + + +def test_charging_schedule_period_type(): + cspt = ChargingSchedulePeriodType( + start_period=0, + limit=32.0, + number_phases=3, + phase_to_use=1 + ) + + new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) + + assert new_cspt.start_period == cspt.start_period + assert new_cspt.limit == cspt.limit + assert new_cspt.number_phases == cspt.number_phases + assert new_cspt.phase_to_use == cspt.phase_to_use + + +def test_charging_station_type(): + cst = ChargingStationType( + model="Station Model X", + vendor_name="Vendor ABC", + serial_number="SN123456", + modem=ModemType( + iccid="89001234567890123456", + imsi="123456789012345" + ), + firmware_version="1.2.3" + ) + + new_cst = to_datatype(ChargingStationType, cst) + + assert new_cst.model == cst.model + assert new_cst.vendor_name == cst.vendor_name + assert new_cst.serial_number == cst.serial_number + assert isinstance(new_cst.modem, dict) + assert new_cst.modem['iccid'] == cst.modem.iccid + assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.firmware_version == cst.firmware_version + + +def test_clear_charging_profile_type(): + ccpt = ClearChargingProfileType( + evse_id=1, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0 + ) + + new_ccpt = to_datatype(ClearChargingProfileType, ccpt) + + assert new_ccpt.evse_id == ccpt.evse_id + assert new_ccpt.charging_profile_purpose == ccpt.charging_profile_purpose + assert new_ccpt.stack_level == ccpt.stack_level + + +def test_clear_monitoring_result_type(): + cmrt = ClearMonitoringResultType( + status="Accepted", + id=123, + status_info=StatusInfoType( + reason_code="Cleared", + additional_info="Successfully cleared monitoring" + ) + ) + + new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) + + assert new_cmrt.status == cmrt.status + assert new_cmrt.id == cmrt.id + assert isinstance(new_cmrt.status_info, dict) + assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code + assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + + +def test_component_type(): + ct = ComponentType( + name="MainController", + instance="instance1", + evse=EVSEType( + id=1, + connector_id=2 + ) + ) + + new_ct = to_datatype(ComponentType, ct) + + assert new_ct.name == ct.name + assert new_ct.instance == ct.instance + assert isinstance(new_ct.evse, dict) + assert new_ct.evse['id'] == ct.evse.id + assert new_ct.evse['connector_id'] == ct.evse.connector_id + + +def test_component_variable_type(): + cvt = ComponentVariableType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_cvt = to_datatype(ComponentVariableType, cvt) + + assert isinstance(new_cvt.component, dict) + assert new_cvt.component['name'] == cvt.component.name + assert new_cvt.component['instance'] == cvt.component.instance + assert isinstance(new_cvt.variable, dict) + assert new_cvt.variable['name'] == cvt.variable.name + assert new_cvt.variable['instance'] == cvt.variable.instance + + +def test_composite_schedule_type(): + cst = CompositeScheduleType( + evse_id=1, + duration=3600, + schedule_start="2024-01-01T10:00:00Z", + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ] + ) + + new_cst = to_datatype(CompositeScheduleType, cst) + + assert new_cst.evse_id == cst.evse_id + assert new_cst.duration == cst.duration + assert new_cst.schedule_start == cst.schedule_start + assert new_cst.charging_rate_unit == cst.charging_rate_unit + assert isinstance(new_cst.charging_schedule_period[0], dict) + assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period + assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + + +def test_consumption_cost_type(): + cct = ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + + new_cct = to_datatype(ConsumptionCostType, cct) + + assert new_cct.start_value == cct.start_value + assert isinstance(new_cct.cost[0], dict) + assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind + assert new_cct.cost[0]['amount'] == cct.cost[0].amount + assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + + +def test_cost_type(): + ct = CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + + new_ct = to_datatype(CostType, ct) + + assert new_ct.cost_kind == ct.cost_kind + assert new_ct.amount == ct.amount + assert new_ct.amount_multiplier == ct.amount_multiplier + + +def test_event_data_type(): + edt = EventDataType( + event_id=1, + timestamp="2024-01-01T10:00:00Z", + trigger="Alerting", + actual_value="High Temperature", + tech_code="TC001", + tech_info="Temperature sensor reading high", + cleared=False, + transaction_id="TX001", + variable_monitoring_id=1, + event_notification_type="HardWiredNotification", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ) + ) + + new_edt = to_datatype(EventDataType, edt) + + assert new_edt.event_id == edt.event_id + assert new_edt.timestamp == edt.timestamp + assert new_edt.trigger == edt.trigger + assert new_edt.actual_value == edt.actual_value + assert new_edt.tech_code == edt.tech_code + assert new_edt.tech_info == edt.tech_info + assert new_edt.cleared == edt.cleared + assert new_edt.transaction_id == edt.transaction_id + assert new_edt.variable_monitoring_id == edt.variable_monitoring_id + assert new_edt.event_notification_type == edt.event_notification_type + assert isinstance(new_edt.component, dict) + assert new_edt.component['name'] == edt.component.name + assert isinstance(new_edt.variable, dict) + assert new_edt.variable['name'] == edt.variable.name + + +def test_firmware_type(): + ft = FirmwareType( + location="https://firmware.example.com/v1.2.3", + retrieve_date_time="2024-01-01T10:00:00Z", + install_date_time="2024-01-01T11:00:00Z", + signing_certificate="MIIB...", + signature="SHA256..." + ) + + new_ft = to_datatype(FirmwareType, ft) + + assert new_ft.location == ft.location + assert new_ft.retrieve_date_time == ft.retrieve_date_time + assert new_ft.install_date_time == ft.install_date_time + assert new_ft.signing_certificate == ft.signing_certificate + assert new_ft.signature == ft.signature + + +def test_get_variable_data_type(): + gvdt = GetVariableDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ), + attribute_type=AttributeType.actual + ) + + new_gvdt = to_datatype(GetVariableDataType, gvdt) + + assert isinstance(new_gvdt.component, dict) + assert new_gvdt.component['name'] == gvdt.component.name + assert new_gvdt.component['instance'] == gvdt.component.instance + assert isinstance(new_gvdt.variable, dict) + assert new_gvdt.variable['name'] == gvdt.variable.name + assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.attribute_type == gvdt.attribute_type + + +def test_get_variable_result_type(): + gvrt = GetVariableResultType( + attribute_status="Accepted", + attribute_type=AttributeType.actual, + attribute_value="100", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_gvrt = to_datatype(GetVariableResultType, gvrt) + + assert new_gvrt.attribute_status == gvrt.attribute_status + assert new_gvrt.attribute_type == gvrt.attribute_type + assert new_gvrt.attribute_value == gvrt.attribute_value + assert isinstance(new_gvrt.component, dict) + assert new_gvrt.component['name'] == gvrt.component.name + assert isinstance(new_gvrt.variable, dict) + assert new_gvrt.variable['name'] == gvrt.variable.name + + +def test_id_token_info_type(): + itit = IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr", + group_id_token=IdTokenType.central, + personal_message=MessageContentType( + format=MessageFormatType.ascii, + content="Welcome back!", + language="en" + ) + ) + + new_itit = to_datatype(IdTokenInfoType, itit) + + assert new_itit.status == itit.status + assert new_itit.cache_expiry_date_time == itit.cache_expiry_date_time + assert new_itit.charging_priority == itit.charging_priority + assert new_itit.language_1 == itit.language_1 + assert new_itit.language_2 == itit.language_2 + assert isinstance(new_itit.group_id_token, str) + assert new_itit.group_id_token == itit.group_id_token + assert isinstance(new_itit.personal_message, dict) + assert new_itit.personal_message['content'] == itit.personal_message.content + + +def test_log_parameters_type(): + lpt = LogParametersType( + remote_location="https://logs.example.com", + oldest_timestamp="2024-01-01T00:00:00Z", + latest_timestamp="2024-01-01T23:59:59Z" + ) + + new_lpt = to_datatype(LogParametersType, lpt) + + assert new_lpt.remote_location == lpt.remote_location + assert new_lpt.oldest_timestamp == lpt.oldest_timestamp + assert new_lpt.latest_timestamp == lpt.latest_timestamp + + +def test_message_info_type(): + mit = MessageInfoType( + id=1, + priority=1, + message=MessageContentType( + format=MessageFormatType.ascii, + content="Important notice", + language="en" + ), + display=ComponentType( + name="MainDisplay", + instance="instance1" + ), + state="Charging" + ) + + new_mit = to_datatype(MessageInfoType, mit) + + assert new_mit.id == mit.id + assert new_mit.priority == mit.priority + assert isinstance(new_mit.message, dict) + assert new_mit.message['content'] == mit.message.content + assert isinstance(new_mit.display, dict) + assert new_mit.display['name'] == mit.display.name + assert new_mit.state == mit.state + + +def test_meter_value_type(): + mvt = MeterValueType( + timestamp="2024-01-01T10:00:00Z", + sampled_value=[ + SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet + ) + ] + ) + + new_mvt = to_datatype(MeterValueType, mvt) + + assert new_mvt.timestamp == mvt.timestamp + assert isinstance(new_mvt.sampled_value[0], dict) + assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + + +def test_modem_type(): + mt = ModemType( + iccid="89012345678901234567", + imsi="123456789012345" + ) + + new_mt = to_datatype(ModemType, mt) + + assert new_mt.iccid == mt.iccid + assert new_mt.imsi == mt.imsi + + +def test_monitoring_data_type(): + mdt = MonitoringDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_monitoring=VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + ) + + new_mdt = to_datatype(MonitoringDataType, mdt) + + assert isinstance(new_mdt.component, dict) + assert new_mdt.component['name'] == mdt.component.name + assert isinstance(new_mdt.variable, dict) + assert new_mdt.variable['name'] == mdt.variable.name + assert isinstance(new_mdt.variable_monitoring, dict) + assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + + +def test_network_connection_profile_type(): + ncpt = NetworkConnectionProfileType( + ocpp_version=OCPPVersionType.ocpp20, + ocpp_transport=OCPPTransportType.json, + ocpp_csms_url="wss://example.com/ocpp", + message_timeout=30, + security_profile=1, + ocpp_interface=OCPPInterfaceType.wired0 + ) + + new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) + + assert new_ncpt.ocpp_version == ncpt.ocpp_version + assert new_ncpt.ocpp_transport == ncpt.ocpp_transport + assert new_ncpt.ocpp_csms_url == ncpt.ocpp_csms_url + assert new_ncpt.message_timeout == ncpt.message_timeout + assert new_ncpt.security_profile == ncpt.security_profile + assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + + +def test_ocsp_request_data_type(): + ordt = OCSPRequestDataType( + hash_algorithm=HashAlgorithmType.sha256, + issuer_name_hash="issuer_hash_value", + issuer_key_hash="issuer_key_hash_value", + serial_number="serial123", + responder_url="http://ocsp.example.com" + ) + + new_ordt = to_datatype(OCSPRequestDataType, ordt) + + assert new_ordt.hash_algorithm == ordt.hash_algorithm + assert new_ordt.issuer_name_hash == ordt.issuer_name_hash + assert new_ordt.issuer_key_hash == ordt.issuer_key_hash + assert new_ordt.serial_number == ordt.serial_number + assert new_ordt.responder_url == ordt.responder_url + + +def test_relative_time_interval_type(): + rtit = RelativeTimeIntervalType( + start=0, + duration=3600 + ) + + new_rtit = to_datatype(RelativeTimeIntervalType, rtit) + + assert new_rtit.start == rtit.start + assert new_rtit.duration == rtit.duration + + +def test_report_data_type(): + rdt = ReportDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_attribute=[ + VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + ], + variable_characteristics=VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + ) + + new_rdt = to_datatype(ReportDataType, rdt) + + assert isinstance(new_rdt.component, dict) + assert new_rdt.component['name'] == rdt.component.name + assert isinstance(new_rdt.variable, dict) + assert new_rdt.variable['name'] == rdt.variable.name + assert isinstance(new_rdt.variable_attribute[0], dict) + assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert isinstance(new_rdt.variable_characteristics, dict) + assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit + assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type + assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + + +def test_sales_tariff_entry_type(): + stet = SalesTariffEntryType( + e_price_level=1, + relative_time_interval=RelativeTimeIntervalType( + start=0, + duration=3600 + ), + consumption_cost=[ + ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + ] + ) + + new_stet = to_datatype(SalesTariffEntryType, stet) + + assert new_stet.e_price_level == stet.e_price_level + assert isinstance(new_stet.relative_time_interval, dict) + assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start + assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert isinstance(new_stet.consumption_cost[0], dict) + assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value + assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) + assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind + assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount + assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + + +def test_sampled_value_type(): + svt = SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet, + unit_of_measure=UnitOfMeasureType( + unit=UnitOfMeasureUnitType.v, + multiplier=0 + ) + ) + + new_svt = to_datatype(SampledValueType, svt) + + assert new_svt.value == svt.value + assert new_svt.context == svt.context + assert new_svt.measurand == svt.measurand + assert new_svt.phase == svt.phase + assert new_svt.location == svt.location + assert isinstance(new_svt.unit_of_measure, dict) + assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + + +def test_set_monitoring_data_type(): + smdt = SetMonitoringDataType( + value=100.0, + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + id=123456 + ) + + new_smdt = to_datatype(SetMonitoringDataType, smdt) + + assert new_smdt.value == smdt.value + assert new_smdt.type == smdt.type + assert new_smdt.severity == smdt.severity + assert isinstance(new_smdt.component, dict) + assert new_smdt.component['name'] == smdt.component.name + assert new_smdt.component['instance'] == smdt.component.instance + assert isinstance(new_smdt.variable, dict) + assert new_smdt.variable['name'] == smdt.variable.name + assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.id == smdt.id + + +def test_unit_of_measure_type(): + uomt = UnitOfMeasureType( + #unit=UnitOfMeasureType.w, + multiplier=1 + ) + + new_uomt = to_datatype(UnitOfMeasureType, uomt) + + assert new_uomt.unit == uomt.unit + assert new_uomt.multiplier == uomt.multiplier + + +def test_variable_attribute_type(): + vat = VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + + new_vat = to_datatype(VariableAttributeType, vat) + + assert new_vat.type == vat.type + assert new_vat.value == vat.value + assert new_vat.mutability == vat.mutability + assert new_vat.persistent == vat.persistent + assert new_vat.constant == vat.constant + + +def test_variable_characteristics_type(): + vct = VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + + new_vct = to_datatype(VariableCharacteristicsType, vct) + + assert new_vct.unit == vct.unit + assert new_vct.data_type == vct.data_type + assert new_vct.min_limit == vct.min_limit + assert new_vct.max_limit == vct.max_limit + assert new_vct.values_list == vct.values_list + assert new_vct.supports_monitoring == vct.supports_monitoring + + +def test_variable_monitoring_type(): + vmt = VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + + new_vmt = to_datatype(VariableMonitoringType, vmt) + + assert new_vmt.id == vmt.id + assert new_vmt.transaction == vmt.transaction + assert new_vmt.value == vmt.value + assert new_vmt.type == vmt.type + assert new_vmt.severity == vmt.severity + + + + + + From 9ff2f1fef3db42066cfe02b542692aead495e39d Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:16:41 -0500 Subject: [PATCH 06/27] fixing formatting, import sorting and make sure all imports are being used --- ocpp/v201/datatypes.py | 4 +- ocpp/v201/enums.py | 4 +- tests/v201/test_v201_data_types.py | 628 +++++++++++++++++------------ 3 files changed, 366 insertions(+), 270 deletions(-) diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 27bb43af0..59c80b24c 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -454,7 +454,7 @@ class IdTokenType: """ id_token: str - type: enums.IdTokenType + type: enums.IdTokenEnumType additional_info: Optional[List[AdditionalInfoType]] = None @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.UnitOfMeasureUnitType] = None + unit: Optional[enums.StandardizedUnitsOfMeasureType] = None multiplier: Optional[int] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2c69e953b..421553890 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -721,7 +721,7 @@ class HashAlgorithmType(StrEnum): sha512 = "SHA512" -class IdTokenType(StrEnum): +class IdTokenEnumType(StrEnum): """ Allowable values of the IdTokenType field. """ @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureUnitType(StrEnum): +class StandardizedUnitsOfMeasureType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 570c8e186..4fe65a15e 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -1,19 +1,92 @@ import json -from dataclasses import asdict +from dataclasses import asdict, dataclass from typing import TypeVar -from ocpp.v201.datatypes import * +from ocpp.v201.datatypes import ( + ACChargingParametersType, + AdditionalInfoType, + APNType, + AuthorizationData, + CertificateHashDataChainType, + CertificateHashDataType, + ChargingLimitType, + ChargingNeedsType, + ChargingProfileCriterionType, + ChargingProfileType, + ChargingSchedulePeriodType, + ChargingScheduleType, + ChargingStationType, + ClearChargingProfileType, + ClearMonitoringResultType, + ComponentType, + ComponentVariableType, + CompositeScheduleType, + ConsumptionCostType, + CostType, + DCChargingParametersType, + EventDataType, + EVSEType, + FirmwareType, + GetVariableDataType, + GetVariableResultType, + IdTokenInfoType, + IdTokenType, + LogParametersType, + MessageContentType, + MessageInfoType, + MeterValueType, + ModemType, + MonitoringDataType, + NetworkConnectionProfileType, + OCSPRequestDataType, + RelativeTimeIntervalType, + ReportDataType, + SalesTariffEntryType, + SampledValueType, + SetMonitoringDataType, + SetMonitoringResultType, + SetVariableResultType, + StatusInfoType, + UnitOfMeasureType, + VariableAttributeType, + VariableCharacteristicsType, + VariableMonitoringType, + VariableType, +) from ocpp.v201.enums import ( - APNAuthenticationType, AttributeType, ChargingProfileKindType, - ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, - EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, - MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, - OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, - ReasonType, SetMonitoringStatusType, SetVariableStatusType, - UnitOfMeasureUnitType, VPNType + APNAuthenticationType, + AttributeType, + AuthorizationStatusType, + ChargingProfileKindType, + ChargingProfilePurposeType, + ChargingRateUnitType, + ChargingStateType, + ClearMonitoringStatusType, + CostKindType, + DataType, + EnergyTransferModeType, + EventNotificationType, + EventTriggerType, + HashAlgorithmType, + IdTokenEnumType, + LocationType, + MeasurandType, + MessageFormatType, + MonitorType, + MutabilityType, + OCPPInterfaceType, + OCPPTransportType, + OCPPVersionType, + PhaseType, + ReadingContextType, + ReasonType, + SetMonitoringStatusType, + SetVariableStatusType, + StandardizedUnitsOfMeasureType, + VPNType, ) -T = TypeVar('T', bound='dataclass') +T = TypeVar("T", bound="dataclass") def to_datatype(cls, dc: T): @@ -25,10 +98,7 @@ def to_datatype(cls, dc: T): def test_ac_charging_parameters_type(): acpt = ACChargingParametersType( - energy_amount=20.5, - ev_min_current=10.0, - ev_max_current=32.0, - ev_max_voltage=400 + energy_amount=20.5, ev_min_current=10.0, ev_max_current=32.0, ev_max_voltage=400 ) new_acpt = to_datatype(ACChargingParametersType, acpt) @@ -41,8 +111,7 @@ def test_ac_charging_parameters_type(): def test_additional_info_type(): ait = AdditionalInfoType( - additional_id_token="additional_token123", - type="type_value" + additional_id_token="additional_token123", type="type_value" ) new_ait = to_datatype(AdditionalInfoType, ait) @@ -54,12 +123,12 @@ def test_additional_info_type(): def test_apn_type(): at = APNType( apn="internet.example.com", - apn_authentication="AUTO", + apn_authentication=APNAuthenticationType.auto, apn_user_name="username", apn_password="password", sim_pin=1234, preferred_network="preferred", - use_only_preferred_network=True + use_only_preferred_network=True, ) new_at = to_datatype(APNType, at) @@ -76,23 +145,32 @@ def test_apn_type(): def test_authorization_data(): ad = AuthorizationData( id_token_info=IdTokenInfoType( - status="Accepted", + status=AuthorizationStatusType.accepted, cache_expiry_date_time="2024-01-01T10:00:00Z", charging_priority=1, language_1="en", - language_2="fr" + language_2="fr", + group_id_token=IdTokenType( + type=IdTokenEnumType.central, + id_token="1234567890", + ), ), - id_token=IdTokenType.iso14443 + id_token=IdTokenEnumType.central, ) new_ad = to_datatype(AuthorizationData, ad) assert isinstance(new_ad.id_token_info, dict) - assert new_ad.id_token_info['status'] == ad.id_token_info.status - assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time - assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority - assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 - assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert new_ad.id_token_info["status"] == ad.id_token_info.status + assert ( + new_ad.id_token_info["cache_expiry_date_time"] + == ad.id_token_info.cache_expiry_date_time + ) + assert ( + new_ad.id_token_info["charging_priority"] == ad.id_token_info.charging_priority + ) + assert new_ad.id_token_info["language_1"] == ad.id_token_info.language_1 + assert new_ad.id_token_info["language_2"] == ad.id_token_info.language_2 assert isinstance(new_ad.id_token, str) assert new_ad.id_token == ad.id_token @@ -104,28 +182,43 @@ def test_certificate_hash_data_chain_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ), child_certificate_hash_data=[ CertificateHashDataType( hash_algorithm="SHA256", issuer_name_hash="child_issuer_hash", issuer_key_hash="child_key_hash", - serial_number="child_serial123" + serial_number="child_serial123", ) - ] + ], ) new_chdct = to_datatype(CertificateHashDataChainType, chdct) assert new_chdct.certificate_type == chdct.certificate_type assert isinstance(new_chdct.certificate_hash_data, dict) - assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm - assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash - assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash - assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert ( + new_chdct.certificate_hash_data["hash_algorithm"] + == chdct.certificate_hash_data.hash_algorithm + ) + assert ( + new_chdct.certificate_hash_data["issuer_name_hash"] + == chdct.certificate_hash_data.issuer_name_hash + ) + assert ( + new_chdct.certificate_hash_data["issuer_key_hash"] + == chdct.certificate_hash_data.issuer_key_hash + ) + assert ( + new_chdct.certificate_hash_data["serial_number"] + == chdct.certificate_hash_data.serial_number + ) assert isinstance(new_chdct.child_certificate_hash_data[0], dict) - assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + assert ( + new_chdct.child_certificate_hash_data[0]["hash_algorithm"] + == chdct.child_certificate_hash_data[0].hash_algorithm + ) def test_certificate_hash_data_type(): @@ -133,7 +226,7 @@ def test_certificate_hash_data_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ) new_chdt = to_datatype(CertificateHashDataType, chdt) @@ -145,10 +238,7 @@ def test_certificate_hash_data_type(): def test_charging_limit_type(): - clt = ChargingLimitType( - charging_limit_source="EMS", - is_grid_critical=True - ) + clt = ChargingLimitType(charging_limit_source="EMS", is_grid_critical=True) new_clt = to_datatype(ChargingLimitType, clt) @@ -161,18 +251,15 @@ def test_charging_needs_type(): requested_energy_transfer=EnergyTransferModeType.dc, departure_time="2024-01-01T10:00:00Z", ac_charging_parameters=ACChargingParametersType( - energy_amount=20, - ev_min_current=10, - ev_max_current=32, - ev_max_voltage=400 + energy_amount=20, ev_min_current=10, ev_max_current=32, ev_max_voltage=400 ), dc_charging_parameters=DCChargingParametersType( ev_max_current=100, ev_max_voltage=500, energy_amount=50, ev_max_power=50000, - state_of_charge=80 - ) + state_of_charge=80, + ), ) new_cnt = to_datatype(ChargingNeedsType, cnt) @@ -180,18 +267,30 @@ def test_charging_needs_type(): assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer assert new_cnt.departure_time == cnt.departure_time assert isinstance(new_cnt.ac_charging_parameters, dict) - assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount - assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert ( + new_cnt.ac_charging_parameters["energy_amount"] + == cnt.ac_charging_parameters.energy_amount + ) + assert ( + new_cnt.ac_charging_parameters["ev_min_current"] + == cnt.ac_charging_parameters.ev_min_current + ) assert isinstance(new_cnt.dc_charging_parameters, dict) - assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current - assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + assert ( + new_cnt.dc_charging_parameters["ev_max_current"] + == cnt.dc_charging_parameters.ev_max_current + ) + assert ( + new_cnt.dc_charging_parameters["state_of_charge"] + == cnt.dc_charging_parameters.state_of_charge + ) def test_charging_profile_criterion_type(): cpct = ChargingProfileCriterionType( charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, stack_level=0, - charging_profile_id=[1, 2, 3] + charging_profile_id=[1, 2, 3], ) new_cpct = to_datatype(ChargingProfileCriterionType, cpct) @@ -213,17 +312,15 @@ def test_charging_profile_type(): charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 + start_period=0, limit=11000.0, number_phases=3 ) ], start_schedule="2024-01-01T10:00:00Z", - duration=3600 + duration=3600, ) ], valid_from="2024-01-01T00:00:00Z", - valid_to="2024-12-31T23:59:59Z" + valid_to="2024-12-31T23:59:59Z", ) new_cpt = to_datatype(ChargingProfileType, cpt) @@ -233,17 +330,14 @@ def test_charging_profile_type(): assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose assert new_cpt.charging_profile_kind == cpt.charging_profile_kind assert isinstance(new_cpt.charging_schedule[0], dict) - assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.charging_schedule[0]["id"] == cpt.charging_schedule[0].id assert new_cpt.valid_from == cpt.valid_from assert new_cpt.valid_to == cpt.valid_to def test_charging_schedule_period_type(): cspt = ChargingSchedulePeriodType( - start_period=0, - limit=32.0, - number_phases=3, - phase_to_use=1 + start_period=0, limit=32.0, number_phases=3, phase_to_use=1 ) new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) @@ -259,11 +353,8 @@ def test_charging_station_type(): model="Station Model X", vendor_name="Vendor ABC", serial_number="SN123456", - modem=ModemType( - iccid="89001234567890123456", - imsi="123456789012345" - ), - firmware_version="1.2.3" + modem=ModemType(iccid="89001234567890123456", imsi="123456789012345"), + firmware_version="1.2.3", ) new_cst = to_datatype(ChargingStationType, cst) @@ -272,8 +363,8 @@ def test_charging_station_type(): assert new_cst.vendor_name == cst.vendor_name assert new_cst.serial_number == cst.serial_number assert isinstance(new_cst.modem, dict) - assert new_cst.modem['iccid'] == cst.modem.iccid - assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.modem["iccid"] == cst.modem.iccid + assert new_cst.modem["imsi"] == cst.modem.imsi assert new_cst.firmware_version == cst.firmware_version @@ -281,7 +372,7 @@ def test_clear_charging_profile_type(): ccpt = ClearChargingProfileType( evse_id=1, charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, - stack_level=0 + stack_level=0, ) new_ccpt = to_datatype(ClearChargingProfileType, ccpt) @@ -293,12 +384,12 @@ def test_clear_charging_profile_type(): def test_clear_monitoring_result_type(): cmrt = ClearMonitoringResultType( - status="Accepted", + status=ClearMonitoringStatusType.accepted, id=123, status_info=StatusInfoType( - reason_code="Cleared", - additional_info="Successfully cleared monitoring" - ) + reason_code=ReasonType.other, + additional_info="Successfully cleared monitoring", + ), ) new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) @@ -306,18 +397,13 @@ def test_clear_monitoring_result_type(): assert new_cmrt.status == cmrt.status assert new_cmrt.id == cmrt.id assert isinstance(new_cmrt.status_info, dict) - assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code - assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + assert new_cmrt.status_info["reason_code"] == cmrt.status_info.reason_code + assert new_cmrt.status_info["additional_info"] == cmrt.status_info.additional_info def test_component_type(): ct = ComponentType( - name="MainController", - instance="instance1", - evse=EVSEType( - id=1, - connector_id=2 - ) + name="MainController", instance="instance1", evse=EVSEType(id=1, connector_id=2) ) new_ct = to_datatype(ComponentType, ct) @@ -325,30 +411,24 @@ def test_component_type(): assert new_ct.name == ct.name assert new_ct.instance == ct.instance assert isinstance(new_ct.evse, dict) - assert new_ct.evse['id'] == ct.evse.id - assert new_ct.evse['connector_id'] == ct.evse.connector_id + assert new_ct.evse["id"] == ct.evse.id + assert new_ct.evse["connector_id"] == ct.evse.connector_id def test_component_variable_type(): cvt = ComponentVariableType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_cvt = to_datatype(ComponentVariableType, cvt) assert isinstance(new_cvt.component, dict) - assert new_cvt.component['name'] == cvt.component.name - assert new_cvt.component['instance'] == cvt.component.instance + assert new_cvt.component["name"] == cvt.component.name + assert new_cvt.component["instance"] == cvt.component.instance assert isinstance(new_cvt.variable, dict) - assert new_cvt.variable['name'] == cvt.variable.name - assert new_cvt.variable['instance'] == cvt.variable.instance + assert new_cvt.variable["name"] == cvt.variable.name + assert new_cvt.variable["instance"] == cvt.variable.instance def test_composite_schedule_type(): @@ -358,12 +438,8 @@ def test_composite_schedule_type(): schedule_start="2024-01-01T10:00:00Z", charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ - ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 - ) - ] + ChargingSchedulePeriodType(start_period=0, limit=11000.0, number_phases=3) + ], ) new_cst = to_datatype(CompositeScheduleType, cst) @@ -373,36 +449,34 @@ def test_composite_schedule_type(): assert new_cst.schedule_start == cst.schedule_start assert new_cst.charging_rate_unit == cst.charging_rate_unit assert isinstance(new_cst.charging_schedule_period[0], dict) - assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period - assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + assert ( + new_cst.charging_schedule_period[0]["start_period"] + == cst.charging_schedule_period[0].start_period + ) + assert ( + new_cst.charging_schedule_period[0]["limit"] + == cst.charging_schedule_period[0].limit + ) def test_consumption_cost_type(): cct = ConsumptionCostType( start_value=0.0, - cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + cost=[CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0)], ) new_cct = to_datatype(ConsumptionCostType, cct) assert new_cct.start_value == cct.start_value assert isinstance(new_cct.cost[0], dict) - assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind - assert new_cct.cost[0]['amount'] == cct.cost[0].amount - assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + assert new_cct.cost[0]["cost_kind"] == cct.cost[0].cost_kind + assert new_cct.cost[0]["amount"] == cct.cost[0].amount + assert new_cct.cost[0]["amount_multiplier"] == cct.cost[0].amount_multiplier def test_cost_type(): ct = CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 + cost_kind=CostKindType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 ) new_ct = to_datatype(CostType, ct) @@ -416,22 +490,16 @@ def test_event_data_type(): edt = EventDataType( event_id=1, timestamp="2024-01-01T10:00:00Z", - trigger="Alerting", + trigger=EventTriggerType.alerting, actual_value="High Temperature", tech_code="TC001", tech_info="Temperature sensor reading high", cleared=False, transaction_id="TX001", variable_monitoring_id=1, - event_notification_type="HardWiredNotification", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ) + event_notification_type=EventNotificationType.hard_wired_notification, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), ) new_edt = to_datatype(EventDataType, edt) @@ -447,9 +515,9 @@ def test_event_data_type(): assert new_edt.variable_monitoring_id == edt.variable_monitoring_id assert new_edt.event_notification_type == edt.event_notification_type assert isinstance(new_edt.component, dict) - assert new_edt.component['name'] == edt.component.name + assert new_edt.component["name"] == edt.component.name assert isinstance(new_edt.variable, dict) - assert new_edt.variable['name'] == edt.variable.name + assert new_edt.variable["name"] == edt.variable.name def test_firmware_type(): @@ -458,7 +526,7 @@ def test_firmware_type(): retrieve_date_time="2024-01-01T10:00:00Z", install_date_time="2024-01-01T11:00:00Z", signing_certificate="MIIB...", - signature="SHA256..." + signature="SHA256...", ) new_ft = to_datatype(FirmwareType, ft) @@ -472,25 +540,19 @@ def test_firmware_type(): def test_get_variable_data_type(): gvdt = GetVariableDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ), - attribute_type=AttributeType.actual + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_type=AttributeType.actual, ) new_gvdt = to_datatype(GetVariableDataType, gvdt) assert isinstance(new_gvdt.component, dict) - assert new_gvdt.component['name'] == gvdt.component.name - assert new_gvdt.component['instance'] == gvdt.component.instance + assert new_gvdt.component["name"] == gvdt.component.name + assert new_gvdt.component["instance"] == gvdt.component.instance assert isinstance(new_gvdt.variable, dict) - assert new_gvdt.variable['name'] == gvdt.variable.name - assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.variable["name"] == gvdt.variable.name + assert new_gvdt.variable["instance"] == gvdt.variable.instance assert new_gvdt.attribute_type == gvdt.attribute_type @@ -499,14 +561,8 @@ def test_get_variable_result_type(): attribute_status="Accepted", attribute_type=AttributeType.actual, attribute_value="100", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_gvrt = to_datatype(GetVariableResultType, gvrt) @@ -515,9 +571,9 @@ def test_get_variable_result_type(): assert new_gvrt.attribute_type == gvrt.attribute_type assert new_gvrt.attribute_value == gvrt.attribute_value assert isinstance(new_gvrt.component, dict) - assert new_gvrt.component['name'] == gvrt.component.name + assert new_gvrt.component["name"] == gvrt.component.name assert isinstance(new_gvrt.variable, dict) - assert new_gvrt.variable['name'] == gvrt.variable.name + assert new_gvrt.variable["name"] == gvrt.variable.name def test_id_token_info_type(): @@ -527,12 +583,10 @@ def test_id_token_info_type(): charging_priority=1, language_1="en", language_2="fr", - group_id_token=IdTokenType.central, + group_id_token=IdTokenEnumType.central, personal_message=MessageContentType( - format=MessageFormatType.ascii, - content="Welcome back!", - language="en" - ) + format=MessageFormatType.ascii, content="Welcome back!", language="en" + ), ) new_itit = to_datatype(IdTokenInfoType, itit) @@ -545,14 +599,14 @@ def test_id_token_info_type(): assert isinstance(new_itit.group_id_token, str) assert new_itit.group_id_token == itit.group_id_token assert isinstance(new_itit.personal_message, dict) - assert new_itit.personal_message['content'] == itit.personal_message.content + assert new_itit.personal_message["content"] == itit.personal_message.content def test_log_parameters_type(): lpt = LogParametersType( remote_location="https://logs.example.com", oldest_timestamp="2024-01-01T00:00:00Z", - latest_timestamp="2024-01-01T23:59:59Z" + latest_timestamp="2024-01-01T23:59:59Z", ) new_lpt = to_datatype(LogParametersType, lpt) @@ -567,15 +621,10 @@ def test_message_info_type(): id=1, priority=1, message=MessageContentType( - format=MessageFormatType.ascii, - content="Important notice", - language="en" - ), - display=ComponentType( - name="MainDisplay", - instance="instance1" + format=MessageFormatType.ascii, content="Important notice", language="en" ), - state="Charging" + display=ComponentType(name="MainDisplay", instance="instance1"), + state=ChargingStateType.charging, ) new_mit = to_datatype(MessageInfoType, mit) @@ -583,9 +632,9 @@ def test_message_info_type(): assert new_mit.id == mit.id assert new_mit.priority == mit.priority assert isinstance(new_mit.message, dict) - assert new_mit.message['content'] == mit.message.content + assert new_mit.message["content"] == mit.message.content assert isinstance(new_mit.display, dict) - assert new_mit.display['name'] == mit.display.name + assert new_mit.display["name"] == mit.display.name assert new_mit.state == mit.state @@ -598,27 +647,24 @@ def test_meter_value_type(): context=ReadingContextType.sample_periodic, measurand=MeasurandType.voltage, phase=PhaseType.l1, - location=LocationType.outlet + location=LocationType.outlet, ) - ] + ], ) new_mvt = to_datatype(MeterValueType, mvt) assert new_mvt.timestamp == mvt.timestamp assert isinstance(new_mvt.sampled_value[0], dict) - assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value - assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context - assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand - assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase - assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + assert new_mvt.sampled_value[0]["value"] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]["context"] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]["measurand"] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]["phase"] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]["location"] == mvt.sampled_value[0].location def test_modem_type(): - mt = ModemType( - iccid="89012345678901234567", - imsi="123456789012345" - ) + mt = ModemType(iccid="89012345678901234567", imsi="123456789012345") new_mt = to_datatype(ModemType, mt) @@ -628,32 +674,26 @@ def test_modem_type(): def test_monitoring_data_type(): mdt = MonitoringDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_monitoring=VariableMonitoringType( id=1, transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 - ) + severity=1, + ), ) new_mdt = to_datatype(MonitoringDataType, mdt) assert isinstance(new_mdt.component, dict) - assert new_mdt.component['name'] == mdt.component.name + assert new_mdt.component["name"] == mdt.component.name assert isinstance(new_mdt.variable, dict) - assert new_mdt.variable['name'] == mdt.variable.name + assert new_mdt.variable["name"] == mdt.variable.name assert isinstance(new_mdt.variable_monitoring, dict) - assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id - assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + assert new_mdt.variable_monitoring["id"] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring["value"] == mdt.variable_monitoring.value def test_network_connection_profile_type(): @@ -663,7 +703,8 @@ def test_network_connection_profile_type(): ocpp_csms_url="wss://example.com/ocpp", message_timeout=30, security_profile=1, - ocpp_interface=OCPPInterfaceType.wired0 + ocpp_interface=OCPPInterfaceType.wired0, + vpn=VPNType.ikev2, ) new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) @@ -674,6 +715,7 @@ def test_network_connection_profile_type(): assert new_ncpt.message_timeout == ncpt.message_timeout assert new_ncpt.security_profile == ncpt.security_profile assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + assert new_ncpt.vpn == ncpt.vpn def test_ocsp_request_data_type(): @@ -682,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com" + responder_url="http://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) @@ -695,10 +737,7 @@ def test_ocsp_request_data_type(): def test_relative_time_interval_type(): - rtit = RelativeTimeIntervalType( - start=0, - duration=3600 - ) + rtit = RelativeTimeIntervalType(start=0, duration=3600) new_rtit = to_datatype(RelativeTimeIntervalType, rtit) @@ -708,81 +747,89 @@ def test_relative_time_interval_type(): def test_report_data_type(): rdt = ReportDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_attribute=[ VariableAttributeType( type=AttributeType.actual, value="25.5", mutability="ReadWrite", persistent=True, - constant=False + constant=False, ) ], variable_characteristics=VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True - ) + supports_monitoring=True, + ), ) new_rdt = to_datatype(ReportDataType, rdt) assert isinstance(new_rdt.component, dict) - assert new_rdt.component['name'] == rdt.component.name + assert new_rdt.component["name"] == rdt.component.name assert isinstance(new_rdt.variable, dict) - assert new_rdt.variable['name'] == rdt.variable.name + assert new_rdt.variable["name"] == rdt.variable.name assert isinstance(new_rdt.variable_attribute[0], dict) - assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type - assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert new_rdt.variable_attribute[0]["type"] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]["value"] == rdt.variable_attribute[0].value assert isinstance(new_rdt.variable_characteristics, dict) - assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit - assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type - assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + assert new_rdt.variable_characteristics["unit"] == rdt.variable_characteristics.unit + assert ( + new_rdt.variable_characteristics["data_type"] + == rdt.variable_characteristics.data_type + ) + assert ( + new_rdt.variable_characteristics["supports_monitoring"] + == rdt.variable_characteristics.supports_monitoring + ) def test_sales_tariff_entry_type(): stet = SalesTariffEntryType( e_price_level=1, - relative_time_interval=RelativeTimeIntervalType( - start=0, - duration=3600 - ), + relative_time_interval=RelativeTimeIntervalType(start=0, duration=3600), consumption_cost=[ ConsumptionCostType( start_value=0.0, cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0) + ], ) - ] + ], ) new_stet = to_datatype(SalesTariffEntryType, stet) assert new_stet.e_price_level == stet.e_price_level assert isinstance(new_stet.relative_time_interval, dict) - assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start - assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert new_stet.relative_time_interval["start"] == stet.relative_time_interval.start + assert ( + new_stet.relative_time_interval["duration"] + == stet.relative_time_interval.duration + ) assert isinstance(new_stet.consumption_cost[0], dict) - assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value - assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) - assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind - assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount - assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + assert ( + new_stet.consumption_cost[0]["start_value"] + == stet.consumption_cost[0].start_value + ) + assert isinstance(new_stet.consumption_cost[0]["cost"][0], dict) + assert ( + new_stet.consumption_cost[0]["cost"][0]["cost_kind"] + == stet.consumption_cost[0].cost[0].cost_kind + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount"] + == stet.consumption_cost[0].cost[0].amount + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount_multiplier"] + == stet.consumption_cost[0].cost[0].amount_multiplier + ) def test_sampled_value_type(): @@ -793,9 +840,8 @@ def test_sampled_value_type(): phase=PhaseType.l1, location=LocationType.outlet, unit_of_measure=UnitOfMeasureType( - unit=UnitOfMeasureUnitType.v, - multiplier=0 - ) + unit=StandardizedUnitsOfMeasureType.v, multiplier=0 + ), ) new_svt = to_datatype(SampledValueType, svt) @@ -806,8 +852,8 @@ def test_sampled_value_type(): assert new_svt.phase == svt.phase assert new_svt.location == svt.location assert isinstance(new_svt.unit_of_measure, dict) - assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit - assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + assert new_svt.unit_of_measure["unit"] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure["multiplier"] == svt.unit_of_measure.multiplier def test_set_monitoring_data_type(): @@ -815,15 +861,9 @@ def test_set_monitoring_data_type(): value=100.0, type=MonitorType.upper_threshold, severity=1, - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), - id=123456 + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + id=123456, ) new_smdt = to_datatype(SetMonitoringDataType, smdt) @@ -832,17 +872,79 @@ def test_set_monitoring_data_type(): assert new_smdt.type == smdt.type assert new_smdt.severity == smdt.severity assert isinstance(new_smdt.component, dict) - assert new_smdt.component['name'] == smdt.component.name - assert new_smdt.component['instance'] == smdt.component.instance + assert new_smdt.component["name"] == smdt.component.name + assert new_smdt.component["instance"] == smdt.component.instance assert isinstance(new_smdt.variable, dict) - assert new_smdt.variable['name'] == smdt.variable.name - assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.variable["name"] == smdt.variable.name + assert new_smdt.variable["instance"] == smdt.variable.instance assert new_smdt.id == smdt.id +def test_set_monitoring_result_type(): + smrt = SetMonitoringResultType( + status=SetMonitoringStatusType.accepted, + id=123, + status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set monitoring" + ), + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + ) + + new_smrt = to_datatype(SetMonitoringResultType, smrt) + + assert new_smrt.status == smrt.status + assert new_smrt.id == smrt.id + assert isinstance(new_smrt.status_info, dict) + assert new_smrt.status_info["reason_code"] == smrt.status_info.reason_code + assert new_smrt.status_info["additional_info"] == smrt.status_info.additional_info + assert new_smrt.type == smrt.type + assert new_smrt.severity == smrt.severity + assert isinstance(new_smrt.component, dict) + assert new_smrt.component["name"] == smrt.component.name + assert new_smrt.component["instance"] == smrt.component.instance + assert isinstance(new_smrt.variable, dict) + assert new_smrt.variable["name"] == smrt.variable.name + assert new_smrt.variable["instance"] == smrt.variable.instance + + +def test_set_variable_result_type(): + svrt = SetVariableResultType( + attribute_type=AttributeType.actual, + attribute_status=SetVariableStatusType.accepted, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set variable" + ), + ) + + new_svrt = to_datatype(SetVariableResultType, svrt) + + assert new_svrt.attribute_type == svrt.attribute_type + assert new_svrt.attribute_status == svrt.attribute_status + assert isinstance(new_svrt.component, dict) + assert new_svrt.component["name"] == svrt.component.name + assert new_svrt.component["instance"] == svrt.component.instance + assert isinstance(new_svrt.variable, dict) + assert new_svrt.variable["name"] == svrt.variable.name + assert new_svrt.variable["instance"] == svrt.variable.instance + assert isinstance(new_svrt.attribute_status_info, dict) + assert ( + new_svrt.attribute_status_info["reason_code"] + == svrt.attribute_status_info.reason_code + ) + assert ( + new_svrt.attribute_status_info["additional_info"] + == svrt.attribute_status_info.additional_info + ) + + def test_unit_of_measure_type(): uomt = UnitOfMeasureType( - #unit=UnitOfMeasureType.w, + # unit=UnitOfMeasureType.w, multiplier=1 ) @@ -856,9 +958,9 @@ def test_variable_attribute_type(): vat = VariableAttributeType( type=AttributeType.actual, value="25.5", - mutability="ReadWrite", + mutability=MutabilityType.read_write, persistent=True, - constant=False + constant=False, ) new_vat = to_datatype(VariableAttributeType, vat) @@ -873,11 +975,11 @@ def test_variable_attribute_type(): def test_variable_characteristics_type(): vct = VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True + supports_monitoring=True, ) new_vct = to_datatype(VariableCharacteristicsType, vct) @@ -896,7 +998,7 @@ def test_variable_monitoring_type(): transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 + severity=1, ) new_vmt = to_datatype(VariableMonitoringType, vmt) @@ -906,9 +1008,3 @@ def test_variable_monitoring_type(): assert new_vmt.value == vmt.value assert new_vmt.type == vmt.type assert new_vmt.severity == vmt.severity - - - - - - From efbf7b1be35ea4d3123b7d9886503810cc99d7f4 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:20:24 -0500 Subject: [PATCH 07/27] fixing formatting errors --- ocpp/v201/datatypes.py | 2 +- ocpp/v201/enums.py | 4 +- tests/v201/test_v201_data_types.py | 628 +++++++++++++++++------------ 3 files changed, 365 insertions(+), 269 deletions(-) diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 1a63ba43f..ab6e5fb79 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -454,7 +454,7 @@ class IdTokenType: """ id_token: str - type: enums.IdTokenType + type: enums.IdTokenEnumType additional_info: Optional[List[AdditionalInfoType]] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2c69e953b..421553890 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -721,7 +721,7 @@ class HashAlgorithmType(StrEnum): sha512 = "SHA512" -class IdTokenType(StrEnum): +class IdTokenEnumType(StrEnum): """ Allowable values of the IdTokenType field. """ @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureUnitType(StrEnum): +class StandardizedUnitsOfMeasureType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 570c8e186..4fe65a15e 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -1,19 +1,92 @@ import json -from dataclasses import asdict +from dataclasses import asdict, dataclass from typing import TypeVar -from ocpp.v201.datatypes import * +from ocpp.v201.datatypes import ( + ACChargingParametersType, + AdditionalInfoType, + APNType, + AuthorizationData, + CertificateHashDataChainType, + CertificateHashDataType, + ChargingLimitType, + ChargingNeedsType, + ChargingProfileCriterionType, + ChargingProfileType, + ChargingSchedulePeriodType, + ChargingScheduleType, + ChargingStationType, + ClearChargingProfileType, + ClearMonitoringResultType, + ComponentType, + ComponentVariableType, + CompositeScheduleType, + ConsumptionCostType, + CostType, + DCChargingParametersType, + EventDataType, + EVSEType, + FirmwareType, + GetVariableDataType, + GetVariableResultType, + IdTokenInfoType, + IdTokenType, + LogParametersType, + MessageContentType, + MessageInfoType, + MeterValueType, + ModemType, + MonitoringDataType, + NetworkConnectionProfileType, + OCSPRequestDataType, + RelativeTimeIntervalType, + ReportDataType, + SalesTariffEntryType, + SampledValueType, + SetMonitoringDataType, + SetMonitoringResultType, + SetVariableResultType, + StatusInfoType, + UnitOfMeasureType, + VariableAttributeType, + VariableCharacteristicsType, + VariableMonitoringType, + VariableType, +) from ocpp.v201.enums import ( - APNAuthenticationType, AttributeType, ChargingProfileKindType, - ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, - EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, - MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, - OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, - ReasonType, SetMonitoringStatusType, SetVariableStatusType, - UnitOfMeasureUnitType, VPNType + APNAuthenticationType, + AttributeType, + AuthorizationStatusType, + ChargingProfileKindType, + ChargingProfilePurposeType, + ChargingRateUnitType, + ChargingStateType, + ClearMonitoringStatusType, + CostKindType, + DataType, + EnergyTransferModeType, + EventNotificationType, + EventTriggerType, + HashAlgorithmType, + IdTokenEnumType, + LocationType, + MeasurandType, + MessageFormatType, + MonitorType, + MutabilityType, + OCPPInterfaceType, + OCPPTransportType, + OCPPVersionType, + PhaseType, + ReadingContextType, + ReasonType, + SetMonitoringStatusType, + SetVariableStatusType, + StandardizedUnitsOfMeasureType, + VPNType, ) -T = TypeVar('T', bound='dataclass') +T = TypeVar("T", bound="dataclass") def to_datatype(cls, dc: T): @@ -25,10 +98,7 @@ def to_datatype(cls, dc: T): def test_ac_charging_parameters_type(): acpt = ACChargingParametersType( - energy_amount=20.5, - ev_min_current=10.0, - ev_max_current=32.0, - ev_max_voltage=400 + energy_amount=20.5, ev_min_current=10.0, ev_max_current=32.0, ev_max_voltage=400 ) new_acpt = to_datatype(ACChargingParametersType, acpt) @@ -41,8 +111,7 @@ def test_ac_charging_parameters_type(): def test_additional_info_type(): ait = AdditionalInfoType( - additional_id_token="additional_token123", - type="type_value" + additional_id_token="additional_token123", type="type_value" ) new_ait = to_datatype(AdditionalInfoType, ait) @@ -54,12 +123,12 @@ def test_additional_info_type(): def test_apn_type(): at = APNType( apn="internet.example.com", - apn_authentication="AUTO", + apn_authentication=APNAuthenticationType.auto, apn_user_name="username", apn_password="password", sim_pin=1234, preferred_network="preferred", - use_only_preferred_network=True + use_only_preferred_network=True, ) new_at = to_datatype(APNType, at) @@ -76,23 +145,32 @@ def test_apn_type(): def test_authorization_data(): ad = AuthorizationData( id_token_info=IdTokenInfoType( - status="Accepted", + status=AuthorizationStatusType.accepted, cache_expiry_date_time="2024-01-01T10:00:00Z", charging_priority=1, language_1="en", - language_2="fr" + language_2="fr", + group_id_token=IdTokenType( + type=IdTokenEnumType.central, + id_token="1234567890", + ), ), - id_token=IdTokenType.iso14443 + id_token=IdTokenEnumType.central, ) new_ad = to_datatype(AuthorizationData, ad) assert isinstance(new_ad.id_token_info, dict) - assert new_ad.id_token_info['status'] == ad.id_token_info.status - assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time - assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority - assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 - assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert new_ad.id_token_info["status"] == ad.id_token_info.status + assert ( + new_ad.id_token_info["cache_expiry_date_time"] + == ad.id_token_info.cache_expiry_date_time + ) + assert ( + new_ad.id_token_info["charging_priority"] == ad.id_token_info.charging_priority + ) + assert new_ad.id_token_info["language_1"] == ad.id_token_info.language_1 + assert new_ad.id_token_info["language_2"] == ad.id_token_info.language_2 assert isinstance(new_ad.id_token, str) assert new_ad.id_token == ad.id_token @@ -104,28 +182,43 @@ def test_certificate_hash_data_chain_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ), child_certificate_hash_data=[ CertificateHashDataType( hash_algorithm="SHA256", issuer_name_hash="child_issuer_hash", issuer_key_hash="child_key_hash", - serial_number="child_serial123" + serial_number="child_serial123", ) - ] + ], ) new_chdct = to_datatype(CertificateHashDataChainType, chdct) assert new_chdct.certificate_type == chdct.certificate_type assert isinstance(new_chdct.certificate_hash_data, dict) - assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm - assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash - assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash - assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert ( + new_chdct.certificate_hash_data["hash_algorithm"] + == chdct.certificate_hash_data.hash_algorithm + ) + assert ( + new_chdct.certificate_hash_data["issuer_name_hash"] + == chdct.certificate_hash_data.issuer_name_hash + ) + assert ( + new_chdct.certificate_hash_data["issuer_key_hash"] + == chdct.certificate_hash_data.issuer_key_hash + ) + assert ( + new_chdct.certificate_hash_data["serial_number"] + == chdct.certificate_hash_data.serial_number + ) assert isinstance(new_chdct.child_certificate_hash_data[0], dict) - assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + assert ( + new_chdct.child_certificate_hash_data[0]["hash_algorithm"] + == chdct.child_certificate_hash_data[0].hash_algorithm + ) def test_certificate_hash_data_type(): @@ -133,7 +226,7 @@ def test_certificate_hash_data_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ) new_chdt = to_datatype(CertificateHashDataType, chdt) @@ -145,10 +238,7 @@ def test_certificate_hash_data_type(): def test_charging_limit_type(): - clt = ChargingLimitType( - charging_limit_source="EMS", - is_grid_critical=True - ) + clt = ChargingLimitType(charging_limit_source="EMS", is_grid_critical=True) new_clt = to_datatype(ChargingLimitType, clt) @@ -161,18 +251,15 @@ def test_charging_needs_type(): requested_energy_transfer=EnergyTransferModeType.dc, departure_time="2024-01-01T10:00:00Z", ac_charging_parameters=ACChargingParametersType( - energy_amount=20, - ev_min_current=10, - ev_max_current=32, - ev_max_voltage=400 + energy_amount=20, ev_min_current=10, ev_max_current=32, ev_max_voltage=400 ), dc_charging_parameters=DCChargingParametersType( ev_max_current=100, ev_max_voltage=500, energy_amount=50, ev_max_power=50000, - state_of_charge=80 - ) + state_of_charge=80, + ), ) new_cnt = to_datatype(ChargingNeedsType, cnt) @@ -180,18 +267,30 @@ def test_charging_needs_type(): assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer assert new_cnt.departure_time == cnt.departure_time assert isinstance(new_cnt.ac_charging_parameters, dict) - assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount - assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert ( + new_cnt.ac_charging_parameters["energy_amount"] + == cnt.ac_charging_parameters.energy_amount + ) + assert ( + new_cnt.ac_charging_parameters["ev_min_current"] + == cnt.ac_charging_parameters.ev_min_current + ) assert isinstance(new_cnt.dc_charging_parameters, dict) - assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current - assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + assert ( + new_cnt.dc_charging_parameters["ev_max_current"] + == cnt.dc_charging_parameters.ev_max_current + ) + assert ( + new_cnt.dc_charging_parameters["state_of_charge"] + == cnt.dc_charging_parameters.state_of_charge + ) def test_charging_profile_criterion_type(): cpct = ChargingProfileCriterionType( charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, stack_level=0, - charging_profile_id=[1, 2, 3] + charging_profile_id=[1, 2, 3], ) new_cpct = to_datatype(ChargingProfileCriterionType, cpct) @@ -213,17 +312,15 @@ def test_charging_profile_type(): charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 + start_period=0, limit=11000.0, number_phases=3 ) ], start_schedule="2024-01-01T10:00:00Z", - duration=3600 + duration=3600, ) ], valid_from="2024-01-01T00:00:00Z", - valid_to="2024-12-31T23:59:59Z" + valid_to="2024-12-31T23:59:59Z", ) new_cpt = to_datatype(ChargingProfileType, cpt) @@ -233,17 +330,14 @@ def test_charging_profile_type(): assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose assert new_cpt.charging_profile_kind == cpt.charging_profile_kind assert isinstance(new_cpt.charging_schedule[0], dict) - assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.charging_schedule[0]["id"] == cpt.charging_schedule[0].id assert new_cpt.valid_from == cpt.valid_from assert new_cpt.valid_to == cpt.valid_to def test_charging_schedule_period_type(): cspt = ChargingSchedulePeriodType( - start_period=0, - limit=32.0, - number_phases=3, - phase_to_use=1 + start_period=0, limit=32.0, number_phases=3, phase_to_use=1 ) new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) @@ -259,11 +353,8 @@ def test_charging_station_type(): model="Station Model X", vendor_name="Vendor ABC", serial_number="SN123456", - modem=ModemType( - iccid="89001234567890123456", - imsi="123456789012345" - ), - firmware_version="1.2.3" + modem=ModemType(iccid="89001234567890123456", imsi="123456789012345"), + firmware_version="1.2.3", ) new_cst = to_datatype(ChargingStationType, cst) @@ -272,8 +363,8 @@ def test_charging_station_type(): assert new_cst.vendor_name == cst.vendor_name assert new_cst.serial_number == cst.serial_number assert isinstance(new_cst.modem, dict) - assert new_cst.modem['iccid'] == cst.modem.iccid - assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.modem["iccid"] == cst.modem.iccid + assert new_cst.modem["imsi"] == cst.modem.imsi assert new_cst.firmware_version == cst.firmware_version @@ -281,7 +372,7 @@ def test_clear_charging_profile_type(): ccpt = ClearChargingProfileType( evse_id=1, charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, - stack_level=0 + stack_level=0, ) new_ccpt = to_datatype(ClearChargingProfileType, ccpt) @@ -293,12 +384,12 @@ def test_clear_charging_profile_type(): def test_clear_monitoring_result_type(): cmrt = ClearMonitoringResultType( - status="Accepted", + status=ClearMonitoringStatusType.accepted, id=123, status_info=StatusInfoType( - reason_code="Cleared", - additional_info="Successfully cleared monitoring" - ) + reason_code=ReasonType.other, + additional_info="Successfully cleared monitoring", + ), ) new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) @@ -306,18 +397,13 @@ def test_clear_monitoring_result_type(): assert new_cmrt.status == cmrt.status assert new_cmrt.id == cmrt.id assert isinstance(new_cmrt.status_info, dict) - assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code - assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + assert new_cmrt.status_info["reason_code"] == cmrt.status_info.reason_code + assert new_cmrt.status_info["additional_info"] == cmrt.status_info.additional_info def test_component_type(): ct = ComponentType( - name="MainController", - instance="instance1", - evse=EVSEType( - id=1, - connector_id=2 - ) + name="MainController", instance="instance1", evse=EVSEType(id=1, connector_id=2) ) new_ct = to_datatype(ComponentType, ct) @@ -325,30 +411,24 @@ def test_component_type(): assert new_ct.name == ct.name assert new_ct.instance == ct.instance assert isinstance(new_ct.evse, dict) - assert new_ct.evse['id'] == ct.evse.id - assert new_ct.evse['connector_id'] == ct.evse.connector_id + assert new_ct.evse["id"] == ct.evse.id + assert new_ct.evse["connector_id"] == ct.evse.connector_id def test_component_variable_type(): cvt = ComponentVariableType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_cvt = to_datatype(ComponentVariableType, cvt) assert isinstance(new_cvt.component, dict) - assert new_cvt.component['name'] == cvt.component.name - assert new_cvt.component['instance'] == cvt.component.instance + assert new_cvt.component["name"] == cvt.component.name + assert new_cvt.component["instance"] == cvt.component.instance assert isinstance(new_cvt.variable, dict) - assert new_cvt.variable['name'] == cvt.variable.name - assert new_cvt.variable['instance'] == cvt.variable.instance + assert new_cvt.variable["name"] == cvt.variable.name + assert new_cvt.variable["instance"] == cvt.variable.instance def test_composite_schedule_type(): @@ -358,12 +438,8 @@ def test_composite_schedule_type(): schedule_start="2024-01-01T10:00:00Z", charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ - ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 - ) - ] + ChargingSchedulePeriodType(start_period=0, limit=11000.0, number_phases=3) + ], ) new_cst = to_datatype(CompositeScheduleType, cst) @@ -373,36 +449,34 @@ def test_composite_schedule_type(): assert new_cst.schedule_start == cst.schedule_start assert new_cst.charging_rate_unit == cst.charging_rate_unit assert isinstance(new_cst.charging_schedule_period[0], dict) - assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period - assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + assert ( + new_cst.charging_schedule_period[0]["start_period"] + == cst.charging_schedule_period[0].start_period + ) + assert ( + new_cst.charging_schedule_period[0]["limit"] + == cst.charging_schedule_period[0].limit + ) def test_consumption_cost_type(): cct = ConsumptionCostType( start_value=0.0, - cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + cost=[CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0)], ) new_cct = to_datatype(ConsumptionCostType, cct) assert new_cct.start_value == cct.start_value assert isinstance(new_cct.cost[0], dict) - assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind - assert new_cct.cost[0]['amount'] == cct.cost[0].amount - assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + assert new_cct.cost[0]["cost_kind"] == cct.cost[0].cost_kind + assert new_cct.cost[0]["amount"] == cct.cost[0].amount + assert new_cct.cost[0]["amount_multiplier"] == cct.cost[0].amount_multiplier def test_cost_type(): ct = CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 + cost_kind=CostKindType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 ) new_ct = to_datatype(CostType, ct) @@ -416,22 +490,16 @@ def test_event_data_type(): edt = EventDataType( event_id=1, timestamp="2024-01-01T10:00:00Z", - trigger="Alerting", + trigger=EventTriggerType.alerting, actual_value="High Temperature", tech_code="TC001", tech_info="Temperature sensor reading high", cleared=False, transaction_id="TX001", variable_monitoring_id=1, - event_notification_type="HardWiredNotification", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ) + event_notification_type=EventNotificationType.hard_wired_notification, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), ) new_edt = to_datatype(EventDataType, edt) @@ -447,9 +515,9 @@ def test_event_data_type(): assert new_edt.variable_monitoring_id == edt.variable_monitoring_id assert new_edt.event_notification_type == edt.event_notification_type assert isinstance(new_edt.component, dict) - assert new_edt.component['name'] == edt.component.name + assert new_edt.component["name"] == edt.component.name assert isinstance(new_edt.variable, dict) - assert new_edt.variable['name'] == edt.variable.name + assert new_edt.variable["name"] == edt.variable.name def test_firmware_type(): @@ -458,7 +526,7 @@ def test_firmware_type(): retrieve_date_time="2024-01-01T10:00:00Z", install_date_time="2024-01-01T11:00:00Z", signing_certificate="MIIB...", - signature="SHA256..." + signature="SHA256...", ) new_ft = to_datatype(FirmwareType, ft) @@ -472,25 +540,19 @@ def test_firmware_type(): def test_get_variable_data_type(): gvdt = GetVariableDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ), - attribute_type=AttributeType.actual + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_type=AttributeType.actual, ) new_gvdt = to_datatype(GetVariableDataType, gvdt) assert isinstance(new_gvdt.component, dict) - assert new_gvdt.component['name'] == gvdt.component.name - assert new_gvdt.component['instance'] == gvdt.component.instance + assert new_gvdt.component["name"] == gvdt.component.name + assert new_gvdt.component["instance"] == gvdt.component.instance assert isinstance(new_gvdt.variable, dict) - assert new_gvdt.variable['name'] == gvdt.variable.name - assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.variable["name"] == gvdt.variable.name + assert new_gvdt.variable["instance"] == gvdt.variable.instance assert new_gvdt.attribute_type == gvdt.attribute_type @@ -499,14 +561,8 @@ def test_get_variable_result_type(): attribute_status="Accepted", attribute_type=AttributeType.actual, attribute_value="100", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_gvrt = to_datatype(GetVariableResultType, gvrt) @@ -515,9 +571,9 @@ def test_get_variable_result_type(): assert new_gvrt.attribute_type == gvrt.attribute_type assert new_gvrt.attribute_value == gvrt.attribute_value assert isinstance(new_gvrt.component, dict) - assert new_gvrt.component['name'] == gvrt.component.name + assert new_gvrt.component["name"] == gvrt.component.name assert isinstance(new_gvrt.variable, dict) - assert new_gvrt.variable['name'] == gvrt.variable.name + assert new_gvrt.variable["name"] == gvrt.variable.name def test_id_token_info_type(): @@ -527,12 +583,10 @@ def test_id_token_info_type(): charging_priority=1, language_1="en", language_2="fr", - group_id_token=IdTokenType.central, + group_id_token=IdTokenEnumType.central, personal_message=MessageContentType( - format=MessageFormatType.ascii, - content="Welcome back!", - language="en" - ) + format=MessageFormatType.ascii, content="Welcome back!", language="en" + ), ) new_itit = to_datatype(IdTokenInfoType, itit) @@ -545,14 +599,14 @@ def test_id_token_info_type(): assert isinstance(new_itit.group_id_token, str) assert new_itit.group_id_token == itit.group_id_token assert isinstance(new_itit.personal_message, dict) - assert new_itit.personal_message['content'] == itit.personal_message.content + assert new_itit.personal_message["content"] == itit.personal_message.content def test_log_parameters_type(): lpt = LogParametersType( remote_location="https://logs.example.com", oldest_timestamp="2024-01-01T00:00:00Z", - latest_timestamp="2024-01-01T23:59:59Z" + latest_timestamp="2024-01-01T23:59:59Z", ) new_lpt = to_datatype(LogParametersType, lpt) @@ -567,15 +621,10 @@ def test_message_info_type(): id=1, priority=1, message=MessageContentType( - format=MessageFormatType.ascii, - content="Important notice", - language="en" - ), - display=ComponentType( - name="MainDisplay", - instance="instance1" + format=MessageFormatType.ascii, content="Important notice", language="en" ), - state="Charging" + display=ComponentType(name="MainDisplay", instance="instance1"), + state=ChargingStateType.charging, ) new_mit = to_datatype(MessageInfoType, mit) @@ -583,9 +632,9 @@ def test_message_info_type(): assert new_mit.id == mit.id assert new_mit.priority == mit.priority assert isinstance(new_mit.message, dict) - assert new_mit.message['content'] == mit.message.content + assert new_mit.message["content"] == mit.message.content assert isinstance(new_mit.display, dict) - assert new_mit.display['name'] == mit.display.name + assert new_mit.display["name"] == mit.display.name assert new_mit.state == mit.state @@ -598,27 +647,24 @@ def test_meter_value_type(): context=ReadingContextType.sample_periodic, measurand=MeasurandType.voltage, phase=PhaseType.l1, - location=LocationType.outlet + location=LocationType.outlet, ) - ] + ], ) new_mvt = to_datatype(MeterValueType, mvt) assert new_mvt.timestamp == mvt.timestamp assert isinstance(new_mvt.sampled_value[0], dict) - assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value - assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context - assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand - assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase - assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + assert new_mvt.sampled_value[0]["value"] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]["context"] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]["measurand"] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]["phase"] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]["location"] == mvt.sampled_value[0].location def test_modem_type(): - mt = ModemType( - iccid="89012345678901234567", - imsi="123456789012345" - ) + mt = ModemType(iccid="89012345678901234567", imsi="123456789012345") new_mt = to_datatype(ModemType, mt) @@ -628,32 +674,26 @@ def test_modem_type(): def test_monitoring_data_type(): mdt = MonitoringDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_monitoring=VariableMonitoringType( id=1, transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 - ) + severity=1, + ), ) new_mdt = to_datatype(MonitoringDataType, mdt) assert isinstance(new_mdt.component, dict) - assert new_mdt.component['name'] == mdt.component.name + assert new_mdt.component["name"] == mdt.component.name assert isinstance(new_mdt.variable, dict) - assert new_mdt.variable['name'] == mdt.variable.name + assert new_mdt.variable["name"] == mdt.variable.name assert isinstance(new_mdt.variable_monitoring, dict) - assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id - assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + assert new_mdt.variable_monitoring["id"] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring["value"] == mdt.variable_monitoring.value def test_network_connection_profile_type(): @@ -663,7 +703,8 @@ def test_network_connection_profile_type(): ocpp_csms_url="wss://example.com/ocpp", message_timeout=30, security_profile=1, - ocpp_interface=OCPPInterfaceType.wired0 + ocpp_interface=OCPPInterfaceType.wired0, + vpn=VPNType.ikev2, ) new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) @@ -674,6 +715,7 @@ def test_network_connection_profile_type(): assert new_ncpt.message_timeout == ncpt.message_timeout assert new_ncpt.security_profile == ncpt.security_profile assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + assert new_ncpt.vpn == ncpt.vpn def test_ocsp_request_data_type(): @@ -682,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com" + responder_url="http://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) @@ -695,10 +737,7 @@ def test_ocsp_request_data_type(): def test_relative_time_interval_type(): - rtit = RelativeTimeIntervalType( - start=0, - duration=3600 - ) + rtit = RelativeTimeIntervalType(start=0, duration=3600) new_rtit = to_datatype(RelativeTimeIntervalType, rtit) @@ -708,81 +747,89 @@ def test_relative_time_interval_type(): def test_report_data_type(): rdt = ReportDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_attribute=[ VariableAttributeType( type=AttributeType.actual, value="25.5", mutability="ReadWrite", persistent=True, - constant=False + constant=False, ) ], variable_characteristics=VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True - ) + supports_monitoring=True, + ), ) new_rdt = to_datatype(ReportDataType, rdt) assert isinstance(new_rdt.component, dict) - assert new_rdt.component['name'] == rdt.component.name + assert new_rdt.component["name"] == rdt.component.name assert isinstance(new_rdt.variable, dict) - assert new_rdt.variable['name'] == rdt.variable.name + assert new_rdt.variable["name"] == rdt.variable.name assert isinstance(new_rdt.variable_attribute[0], dict) - assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type - assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert new_rdt.variable_attribute[0]["type"] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]["value"] == rdt.variable_attribute[0].value assert isinstance(new_rdt.variable_characteristics, dict) - assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit - assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type - assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + assert new_rdt.variable_characteristics["unit"] == rdt.variable_characteristics.unit + assert ( + new_rdt.variable_characteristics["data_type"] + == rdt.variable_characteristics.data_type + ) + assert ( + new_rdt.variable_characteristics["supports_monitoring"] + == rdt.variable_characteristics.supports_monitoring + ) def test_sales_tariff_entry_type(): stet = SalesTariffEntryType( e_price_level=1, - relative_time_interval=RelativeTimeIntervalType( - start=0, - duration=3600 - ), + relative_time_interval=RelativeTimeIntervalType(start=0, duration=3600), consumption_cost=[ ConsumptionCostType( start_value=0.0, cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0) + ], ) - ] + ], ) new_stet = to_datatype(SalesTariffEntryType, stet) assert new_stet.e_price_level == stet.e_price_level assert isinstance(new_stet.relative_time_interval, dict) - assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start - assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert new_stet.relative_time_interval["start"] == stet.relative_time_interval.start + assert ( + new_stet.relative_time_interval["duration"] + == stet.relative_time_interval.duration + ) assert isinstance(new_stet.consumption_cost[0], dict) - assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value - assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) - assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind - assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount - assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + assert ( + new_stet.consumption_cost[0]["start_value"] + == stet.consumption_cost[0].start_value + ) + assert isinstance(new_stet.consumption_cost[0]["cost"][0], dict) + assert ( + new_stet.consumption_cost[0]["cost"][0]["cost_kind"] + == stet.consumption_cost[0].cost[0].cost_kind + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount"] + == stet.consumption_cost[0].cost[0].amount + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount_multiplier"] + == stet.consumption_cost[0].cost[0].amount_multiplier + ) def test_sampled_value_type(): @@ -793,9 +840,8 @@ def test_sampled_value_type(): phase=PhaseType.l1, location=LocationType.outlet, unit_of_measure=UnitOfMeasureType( - unit=UnitOfMeasureUnitType.v, - multiplier=0 - ) + unit=StandardizedUnitsOfMeasureType.v, multiplier=0 + ), ) new_svt = to_datatype(SampledValueType, svt) @@ -806,8 +852,8 @@ def test_sampled_value_type(): assert new_svt.phase == svt.phase assert new_svt.location == svt.location assert isinstance(new_svt.unit_of_measure, dict) - assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit - assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + assert new_svt.unit_of_measure["unit"] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure["multiplier"] == svt.unit_of_measure.multiplier def test_set_monitoring_data_type(): @@ -815,15 +861,9 @@ def test_set_monitoring_data_type(): value=100.0, type=MonitorType.upper_threshold, severity=1, - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), - id=123456 + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + id=123456, ) new_smdt = to_datatype(SetMonitoringDataType, smdt) @@ -832,17 +872,79 @@ def test_set_monitoring_data_type(): assert new_smdt.type == smdt.type assert new_smdt.severity == smdt.severity assert isinstance(new_smdt.component, dict) - assert new_smdt.component['name'] == smdt.component.name - assert new_smdt.component['instance'] == smdt.component.instance + assert new_smdt.component["name"] == smdt.component.name + assert new_smdt.component["instance"] == smdt.component.instance assert isinstance(new_smdt.variable, dict) - assert new_smdt.variable['name'] == smdt.variable.name - assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.variable["name"] == smdt.variable.name + assert new_smdt.variable["instance"] == smdt.variable.instance assert new_smdt.id == smdt.id +def test_set_monitoring_result_type(): + smrt = SetMonitoringResultType( + status=SetMonitoringStatusType.accepted, + id=123, + status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set monitoring" + ), + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + ) + + new_smrt = to_datatype(SetMonitoringResultType, smrt) + + assert new_smrt.status == smrt.status + assert new_smrt.id == smrt.id + assert isinstance(new_smrt.status_info, dict) + assert new_smrt.status_info["reason_code"] == smrt.status_info.reason_code + assert new_smrt.status_info["additional_info"] == smrt.status_info.additional_info + assert new_smrt.type == smrt.type + assert new_smrt.severity == smrt.severity + assert isinstance(new_smrt.component, dict) + assert new_smrt.component["name"] == smrt.component.name + assert new_smrt.component["instance"] == smrt.component.instance + assert isinstance(new_smrt.variable, dict) + assert new_smrt.variable["name"] == smrt.variable.name + assert new_smrt.variable["instance"] == smrt.variable.instance + + +def test_set_variable_result_type(): + svrt = SetVariableResultType( + attribute_type=AttributeType.actual, + attribute_status=SetVariableStatusType.accepted, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set variable" + ), + ) + + new_svrt = to_datatype(SetVariableResultType, svrt) + + assert new_svrt.attribute_type == svrt.attribute_type + assert new_svrt.attribute_status == svrt.attribute_status + assert isinstance(new_svrt.component, dict) + assert new_svrt.component["name"] == svrt.component.name + assert new_svrt.component["instance"] == svrt.component.instance + assert isinstance(new_svrt.variable, dict) + assert new_svrt.variable["name"] == svrt.variable.name + assert new_svrt.variable["instance"] == svrt.variable.instance + assert isinstance(new_svrt.attribute_status_info, dict) + assert ( + new_svrt.attribute_status_info["reason_code"] + == svrt.attribute_status_info.reason_code + ) + assert ( + new_svrt.attribute_status_info["additional_info"] + == svrt.attribute_status_info.additional_info + ) + + def test_unit_of_measure_type(): uomt = UnitOfMeasureType( - #unit=UnitOfMeasureType.w, + # unit=UnitOfMeasureType.w, multiplier=1 ) @@ -856,9 +958,9 @@ def test_variable_attribute_type(): vat = VariableAttributeType( type=AttributeType.actual, value="25.5", - mutability="ReadWrite", + mutability=MutabilityType.read_write, persistent=True, - constant=False + constant=False, ) new_vat = to_datatype(VariableAttributeType, vat) @@ -873,11 +975,11 @@ def test_variable_attribute_type(): def test_variable_characteristics_type(): vct = VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True + supports_monitoring=True, ) new_vct = to_datatype(VariableCharacteristicsType, vct) @@ -896,7 +998,7 @@ def test_variable_monitoring_type(): transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 + severity=1, ) new_vmt = to_datatype(VariableMonitoringType, vmt) @@ -906,9 +1008,3 @@ def test_variable_monitoring_type(): assert new_vmt.value == vmt.value assert new_vmt.type == vmt.type assert new_vmt.severity == vmt.severity - - - - - - From ef2907a275b3e82af354e9d4be5392709653d9b3 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:31:39 -0500 Subject: [PATCH 08/27] even though it's a fake url, flagged as issue by sonarqube --- tests/v201/test_v201_data_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 4fe65a15e..735aa3192 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -724,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com", + responder_url="https://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) From d8553256309f944a89dd2a226b7562748c7de73a Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:33:54 -0500 Subject: [PATCH 09/27] fake url is being flagged by sonarqube as insecure --- tests/v201/test_v201_data_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 4fe65a15e..735aa3192 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -724,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com", + responder_url="https://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) From e53d73c7a5bd9f243dc177e25c74670eec6daf43 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Tue, 26 Nov 2024 10:07:45 -0500 Subject: [PATCH 10/27] adding deprecation warnings for enums IdTokenType and UnitOfMeasureType. eliminates breaking change. --- ocpp/v201/enums.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 421553890..3a0449572 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -10,6 +10,26 @@ class StrEnum(str, Enum): # pragma: no cover pass # pragma: no cover +class DeprecatedEnumWrapper: + """ + Since enums can't be subclassed in order to add a deprecation warning, + this class is included to help warn users of deprecated enums. + """ + + def __init__(self, enum_class, alias_name): + self.enum_class = enum_class + self.alias_name = alias_name + + def __getattr__(self, name): + warn( + ( + f"Enum '{self.alias_name}' is deprecated, " + + "instead use '{self.enum_class.__name__}'" + ) + ) + return getattr(self.enum_class, name) + + class Action(StrEnum): """An Action is a required part of a Call message.""" @@ -736,6 +756,9 @@ class IdTokenEnumType(StrEnum): no_authorization = "NoAuthorization" +IdTokenType = DeprecatedEnumWrapper(IdTokenEnumType, "IdTokenType") + + class InstallCertificateStatusType(StrEnum): """ InstallCertificateStatusEnumType is used by @@ -1364,6 +1387,11 @@ class StandardizedUnitsOfMeasureType(StrEnum): k = "K" +UnitOfMeasureType = DeprecatedEnumWrapper( + StandardizedUnitsOfMeasureType, "UnitOfMeasureType" +) + + class StatusInfoReasonType(StrEnum): """ Standardized reason codes for StatusInfo defined in Appendix 5. v1.3 From 051aa939dd04bf2021d6f7b3d2e7c98937301cd5 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Tue, 26 Nov 2024 10:17:40 -0500 Subject: [PATCH 11/27] removing files associated with a different pull request --- .github/pull_request_template.md | 21 --------- CODE_OF_CONDUCT.md | 74 -------------------------------- CONTRIBUTING.md | 41 ------------------ SECURITY.md | 33 -------------- SUPPORT.md | 34 --------------- 5 files changed, 203 deletions(-) delete mode 100644 .github/pull_request_template.md delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 SECURITY.md delete mode 100644 SUPPORT.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 2e8477f4b..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,21 +0,0 @@ -### Changes included in this PR - -*(Bug fix, feature, docs update, ...)* - -### Current behavior - -*Link to an open issue here...* - -### New behavior - -*If this is a feature change, describe the new behavior* - -### Impact - -*Describe breaking changes, including changes a users might need to make due to this PR* - -### Checklist - -1. [ ] Does your submission pass the existing tests? -2. [ ] Are there new tests that cover these additions/changes? -3. [ ] Have you linted your code locally before submission? diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 86a391351..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at {{ email }}. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index b0037efe8..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,41 +0,0 @@ -## Contributing - -[fork]: /fork -[pr]: /compare -[style]: https://standardjs.com/ -[code-of-conduct]: CODE_OF_CONDUCT.md - -Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. - -Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. - -## Issues and PRs - -If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them. - -We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR. - -Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you. - -## Submitting a pull request - -1. [Fork][fork] and clone the repository. -1. Create a new branch: `git checkout -b my-branch-name`. -1. Configure and install the dependencies: `poetry install`. -1. Make sure the tests pass on your machine: `make install & make tests` -1. Make your change, add tests, and make sure the tests still pass. -1. Push to your fork and [submit a pull request][pr] and complete the information in the pull request template. - -## Linting requirements - -using `make install & make tests` will also run the following linters: - -- [Black: The uncompromising Python code formatter](https://black.readthedocs.io/en/stable/) -- [isort your imports, so you don't have to](https://pycqa.github.io/isort/) -- [flake8: Your Tool For Style Guide Enforcement](https://flake8.pycqa.org/en/latest/) - -## Resources - -- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) -- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) -- [GitHub Help](https://help.github.com) diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index bd76a0f69..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,33 +0,0 @@ -# Security Policy - -This document outlines security procedures and general policies for this OCPP project. - -## Supported Versions - -The currently supported versions of this OCPP project are: - -| Version | Supported | -|----------| ------------------ | -| 2.0.0 | :white_check_mark: | -| 0.26.0 | :white_check_mark: | -| < 0.26.0 | :x: | - -## Reporting a Vulnerability - -Please include the requested information listed below (as much as you can provide) to help -us better understand the nature and scope of the possible issue: - -- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) -- Full paths of source file(s) related to the manifestation of the issue -- The location of the affected source code (tag/branch/commit or direct URL) -- Any special configuration required to reproduce the issue -- Step-by-step instructions to reproduce the issue -- Proof-of-concept or exploit code (if possible) -- Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -## Comments on this Policy - -If you have suggestions on how this process could be improved please submit a -pull request. Thanks! diff --git a/SUPPORT.md b/SUPPORT.md deleted file mode 100644 index 72b64a6c6..000000000 --- a/SUPPORT.md +++ /dev/null @@ -1,34 +0,0 @@ -# Support - -This article explains where to get help with this OCPP project. -Please read through the following guidelines. - -> 👉 **Note**: before participating in our community, please read our -> [code of conduct][coc]. -> By interacting with this repository, organization, or community you agree to -> abide by its terms. - -## Asking quality questions - -Questions can go to [GitHub discussions][chat]. - -Help us help you! -Spend time framing questions and add links and resources. -Spending the extra time up front can help save everyone time in the long run. -Here are some tips: - -* Search to find out if a similar question has been asked or a similar issue has been reported -* Check to see if a PR is already in progress for the issue you want to raise -* Try to define what you need help with: - * Is there something in particular you want to do? - * What problem are you encountering and what steps have you taken to try - and fix it? - * Is there a concept you don’t understand? -* Provide sample code, such as a [CodeSandbox][cs] or video, if possible -* Screenshots can help, but if there’s important text such as code or error - messages in them, please also provide those as text -* The more time you put into asking your question, the better we can help you - -## Contributions - -See [`contributing.md`][contributing] on how to contribute. From be6cc644fb63b1e6ad719e94bb4d6948303b8b2d Mon Sep 17 00:00:00 2001 From: "Dennis Lambe Jr." Date: Fri, 5 Jan 2024 10:12:24 -0500 Subject: [PATCH 12/27] v201:call,call_result,datatypes: complete and corrected type annotations --- ocpp/v201/call.py | 146 ++++++++++++++++---------------- ocpp/v201/call_result.py | 176 ++++++++++++++++++++------------------- ocpp/v201/datatypes.py | 2 +- 3 files changed, 164 insertions(+), 160 deletions(-) diff --git a/ocpp/v201/call.py b/ocpp/v201/call.py index ddc681606..34218d9b9 100644 --- a/ocpp/v201/call.py +++ b/ocpp/v201/call.py @@ -2,19 +2,21 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional +from ocpp.v201 import enums +from ocpp.v201 import datatypes @dataclass class Authorize: - id_token: Dict + id_token: datatypes.IdTokenType certificate: Optional[str] = None - iso15118_certificate_hash_data: Optional[List] = None + iso15118_certificate_hash_data: Optional[List[datatypes.OCSPRequestDataType]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class BootNotification: - charging_station: Dict - reason: str + charging_station: datatypes.ChargingStationType + reason: enums.BootReasonType custom_data: Optional[Dict[str, Any]] = None @@ -27,14 +29,14 @@ class CancelReservation: @dataclass class CertificateSigned: certificate_chain: str - certificate_type: Optional[str] = None + certificate_type: Optional[enums.CertificateSigningUseType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - operational_status: str - evse: Optional[Dict] = None + operational_status: enums.OperationalStatusType + evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None @@ -46,7 +48,7 @@ class ClearCache: @dataclass class ClearChargingProfile: charging_profile_id: Optional[int] = None - charging_profile_criteria: Optional[Dict] = None + charging_profile_criteria: Optional[datatypes.ClearChargingProfileType] = None custom_data: Optional[Dict[str, Any]] = None @@ -58,13 +60,13 @@ class ClearDisplayMessage: @dataclass class ClearVariableMonitoring: - id: List + id: List[int] custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearedChargingLimit: - charging_limit_source: str + charging_limit_source: enums.ChargingLimitSourceType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -81,8 +83,8 @@ class CustomerInformation: request_id: int report: bool clear: bool - customer_certificate: Optional[Dict] = None - id_token: Optional[Dict] = None + customer_certificate: Optional[datatypes.CertificateHashDataType] = None + id_token: Optional[datatypes.IdTokenType] = None customer_identifier: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @@ -97,13 +99,13 @@ class DataTransfer: @dataclass class DeleteCertificate: - certificate_hash_data: Dict + certificate_hash_data: datatypes.CertificateHashDataType custom_data: Optional[Dict[str, Any]] = None @dataclass class FirmwareStatusNotification: - status: str + status: enums.FirmwareStatusType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -111,7 +113,7 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: iso15118_schema_version: str - action: str + action: enums.CertificateActionType exi_request: str custom_data: Optional[Dict[str, Any]] = None @@ -119,20 +121,20 @@ class Get15118EVCertificate: @dataclass class GetBaseReport: request_id: int - report_base: str + report_base: enums.ReportBaseType custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCertificateStatus: - ocsp_request_data: Dict + ocsp_request_data: datatypes.OCSPRequestDataType custom_data: Optional[Dict[str, Any]] = None @dataclass class GetChargingProfiles: request_id: int - charging_profile: Dict + charging_profile: datatypes.ChargingProfileCriterionType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -141,22 +143,22 @@ class GetChargingProfiles: class GetCompositeSchedule: duration: int evse_id: int - charging_rate_unit: Optional[str] = None + charging_rate_unit: Optional[enums.ChargingRateUnitType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetDisplayMessages: request_id: int - id: Optional[List] = None - priority: Optional[str] = None - state: Optional[str] = None + id: Optional[List[int]] = None + priority: Optional[enums.MessagePriorityType] = None + state: Optional[enums.MessageStateType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - certificate_type: Optional[List] = None + certificate_type: Optional[List[enums.GetCertificateIdUseType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -167,8 +169,8 @@ class GetLocalListVersion: @dataclass class GetLog: - log: Dict - log_type: str + log: datatypes.LogParametersType + log_type: enums.LogType request_id: int retries: Optional[int] = None retry_interval: Optional[int] = None @@ -178,16 +180,16 @@ class GetLog: @dataclass class GetMonitoringReport: request_id: int - component_variable: Optional[List] = None - monitoring_criteria: Optional[List] = None + component_variable: Optional[List[datatypes.ComponentVariableType]] = None + monitoring_criteria: Optional[List[enums.MonitoringCriterionType]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetReport: request_id: int - component_variable: Optional[List] = None - component_criteria: Optional[List] = None + component_variable: Optional[List[datatypes.ComponentVariableType]] = None + component_criteria: Optional[List[enums.ComponentCriterionType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -199,7 +201,7 @@ class GetTransactionStatus: @dataclass class GetVariables: - get_variable_data: List + get_variable_data: List[datatypes.GetVariableDataType] custom_data: Optional[Dict[str, Any]] = None @@ -210,14 +212,14 @@ class Heartbeat: @dataclass class InstallCertificate: - certificate_type: str + certificate_type: enums.InstallCertificateUseType certificate: str custom_data: Optional[Dict[str, Any]] = None @dataclass class LogStatusNotification: - status: str + status: enums.UploadLogStatusType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -225,14 +227,14 @@ class LogStatusNotification: @dataclass class MeterValues: evse_id: int - meter_value: List + meter_value: List[datatypes.MeterValueType] custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyChargingLimit: - charging_limit: Dict - charging_schedule: Optional[List] = None + charging_limit: datatypes.ChargingLimitType + charging_schedule: Optional[List[datatypes.ChargingScheduleType]] = None evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -250,14 +252,14 @@ class NotifyCustomerInformation: @dataclass class NotifyDisplayMessages: request_id: int - message_info: Optional[List] = None + message_info: Optional[List[datatypes.MessageInfoType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyEVChargingNeeds: - charging_needs: Dict + charging_needs: datatypes.ChargingNeedsType evse_id: int max_schedule_tuples: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -266,7 +268,7 @@ class NotifyEVChargingNeeds: @dataclass class NotifyEVChargingSchedule: time_base: str - charging_schedule: Dict + charging_schedule: datatypes.ChargingScheduleType evse_id: int custom_data: Optional[Dict[str, Any]] = None @@ -275,7 +277,7 @@ class NotifyEVChargingSchedule: class NotifyEvent: generated_at: str seq_no: int - event_data: List + event_data: List[datatypes.EventDataType] tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -285,7 +287,7 @@ class NotifyMonitoringReport: request_id: int seq_no: int generated_at: str - monitor: Optional[List] = None + monitor: Optional[List[datatypes.MonitoringDataType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -295,7 +297,7 @@ class NotifyReport: request_id: int generated_at: str seq_no: int - report_data: Optional[List] = None + report_data: Optional[List[datatypes.ReportDataType]] = None tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -312,8 +314,8 @@ class PublishFirmware: @dataclass class PublishFirmwareStatusNotification: - status: str - location: Optional[List] = None + status: enums.PublishFirmwareStatusType + location: Optional[List[str]] = None request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -321,8 +323,8 @@ class PublishFirmwareStatusNotification: @dataclass class ReportChargingProfiles: request_id: int - charging_limit_source: str - charging_profile: List + charging_limit_source: enums.ChargingLimitSourceType + charging_profile: List[datatypes.ChargingProfileType] evse_id: int tbc: Optional[bool] = None custom_data: Optional[Dict[str, Any]] = None @@ -330,11 +332,11 @@ class ReportChargingProfiles: @dataclass class RequestStartTransaction: - id_token: Dict + id_token: datatypes.IdTokenType remote_start_id: int evse_id: Optional[int] = None - group_id_token: Optional[Dict] = None - charging_profile: Optional[Dict] = None + group_id_token: Optional[datatypes.IdTokenType] = None + charging_profile: Optional[datatypes.ChargingProfileType] = None custom_data: Optional[Dict[str, Any]] = None @@ -347,7 +349,7 @@ class RequestStopTransaction: @dataclass class ReservationStatusUpdate: reservation_id: int - reservation_update_status: str + reservation_update_status: enums.ReservationUpdateStatusType custom_data: Optional[Dict[str, Any]] = None @@ -355,16 +357,16 @@ class ReservationStatusUpdate: class ReserveNow: id: int expiry_date_time: str - id_token: Dict - connector_type: Optional[str] = None + id_token: datatypes.IdTokenType + connector_type: Optional[enums.ConnectorType] = None evse_id: Optional[int] = None - group_id_token: Optional[Dict] = None + group_id_token: Optional[datatypes.IdTokenType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class Reset: - type: str + type: enums.ResetType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -380,27 +382,27 @@ class SecurityEventNotification: @dataclass class SendLocalList: version_number: int - update_type: str - local_authorization_list: Optional[List] = None + update_type: enums.UpdateType + local_authorization_list: Optional[List[datatypes.AuthorizationData]] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetChargingProfile: evse_id: int - charging_profile: Dict + charging_profile: datatypes.ChargingProfileType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetDisplayMessage: - message: Dict + message: datatypes.MessageInfoType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringBase: - monitoring_base: str + monitoring_base: enums.MonitorBaseType custom_data: Optional[Dict[str, Any]] = None @@ -413,33 +415,33 @@ class SetMonitoringLevel: @dataclass class SetNetworkProfile: configuration_slot: int - connection_data: Dict + connection_data: datatypes.NetworkConnectionProfileType custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariableMonitoring: - set_monitoring_data: List + set_monitoring_data: List[datatypes.SetMonitoringDataType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariables: - set_variable_data: List + set_variable_data: List[datatypes.SetVariableDataType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SignCertificate: csr: str - certificate_type: Optional[str] = None + certificate_type: Optional[enums.CertificateSigningUseType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class StatusNotification: timestamp: str - connector_status: str + connector_status: enums.ConnectorStatusType evse_id: int connector_id: int custom_data: Optional[Dict[str, Any]] = None @@ -447,25 +449,25 @@ class StatusNotification: @dataclass class TransactionEvent: - event_type: str + event_type: enums.TransactionEventType timestamp: str - trigger_reason: str + trigger_reason: enums.TriggerReasonType seq_no: int - transaction_info: Dict - meter_value: Optional[List] = None + transaction_info: datatypes.TransactionType + meter_value: Optional[List[datatypes.MeterValueType]] = None offline: Optional[bool] = None number_of_phases_used: Optional[int] = None cable_max_current: Optional[int] = None reservation_id: Optional[int] = None - evse: Optional[Dict] = None - id_token: Optional[Dict] = None + evse: Optional[datatypes.EVSEType] = None + id_token: Optional[datatypes.IdTokenType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class TriggerMessage: - requested_message: str - evse: Optional[Dict] = None + requested_message: enums.MessageTriggerType + evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None @@ -485,7 +487,7 @@ class UnpublishFirmware: @dataclass class UpdateFirmware: request_id: int - firmware: Dict + firmware: datatypes.FirmwareType retries: Optional[int] = None retry_interval: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index 9bf387b26..d9aeeed3b 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -2,11 +2,13 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional +from ocpp.v201 import enums +from ocpp.v201 import datatypes @dataclass class Authorize: - id_token_info: Dict - certificate_status: Optional[str] = None + id_token_info: datatypes.IdTokenInfoType + certificate_status: Optional[enums.AuthorizeCertificateStatusType] = None custom_data: Optional[Dict[str, Any]] = None @@ -14,56 +16,56 @@ class Authorize: class BootNotification: current_time: str interval: int - status: str - status_info: Optional[Dict] = None + status: enums.RegistrationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CancelReservation: - status: str - status_info: Optional[Dict] = None + status: enums.CancelReservationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CertificateSigned: - status: str - status_info: Optional[Dict] = None + status: enums.CertificateSignedStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - status: str - status_info: Optional[Dict] = None + status: enums.ChangeAvailabilityStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearCache: - status: str - status_info: Optional[Dict] = None + status: enums.ClearCacheStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearChargingProfile: - status: str - status_info: Optional[Dict] = None + status: enums.ClearChargingProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearDisplayMessage: - status: str - status_info: Optional[Dict] = None + status: enums.ClearMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearVariableMonitoring: - clear_monitoring_result: List + clear_monitoring_result: List[enums.ClearMonitoringStatusType] custom_data: Optional[Dict[str, Any]] = None @@ -79,23 +81,23 @@ class CostUpdated: @dataclass class CustomerInformation: - status: str - status_info: Optional[Dict] = None + status: enums.CustomerInformationStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class DataTransfer: - status: str - status_info: Optional[Dict] = None + status: enums.DataTransferStatusType + status_info: Optional[datatypes.StatusInfoType] = None data: Optional[Any] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class DeleteCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.DeleteCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -106,54 +108,54 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: - status: str + status: enums.Iso15118EVCertificateStatusType exi_response: str - status_info: Optional[Dict] = None + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetBaseReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCertificateStatus: - status: str - status_info: Optional[Dict] = None + status: enums.GetCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None ocsp_result: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetChargingProfiles: - status: str - status_info: Optional[Dict] = None + status: enums.GetChargingProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCompositeSchedule: - status: str - status_info: Optional[Dict] = None - schedule: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None + schedule: Optional[datatypes.CompositeScheduleType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetDisplayMessages: - status: str - status_info: Optional[Dict] = None + status: enums.GetDisplayMessagesStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - status: str - status_info: Optional[Dict] = None - certificate_hash_data_chain: Optional[List] = None + status: enums.GetInstalledCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None + certificate_hash_data_chain: Optional[List[datatypes.CertificateHashDataChainType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -165,23 +167,23 @@ class GetLocalListVersion: @dataclass class GetLog: - status: str - status_info: Optional[Dict] = None + status: enums.LogStatusType + status_info: Optional[datatypes.StatusInfoType] = None filename: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetMonitoringReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetReport: - status: str - status_info: Optional[Dict] = None + status: enums.GenericDeviceModelStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -194,7 +196,7 @@ class GetTransactionStatus: @dataclass class GetVariables: - get_variable_result: List + get_variable_result: List[datatypes.GetVariableResultType] custom_data: Optional[Dict[str, Any]] = None @@ -206,8 +208,8 @@ class Heartbeat: @dataclass class InstallCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.InstallCertificateStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -238,15 +240,15 @@ class NotifyDisplayMessages: @dataclass class NotifyEVChargingNeeds: - status: str - status_info: Optional[Dict] = None + status: enums.NotifyEVChargingNeedsStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyEVChargingSchedule: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -267,8 +269,8 @@ class NotifyReport: @dataclass class PublishFirmware: - status: str - status_info: Optional[Dict] = None + status: enums.PublishFirmwareStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -284,16 +286,16 @@ class ReportChargingProfiles: @dataclass class RequestStartTransaction: - status: str - status_info: Optional[Dict] = None + status: enums.RequestStartStopStatusType + status_info: Optional[datatypes.StatusInfoType] = None transaction_id: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class RequestStopTransaction: - status: str - status_info: Optional[Dict] = None + status: enums.RequestStartStopStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -304,15 +306,15 @@ class ReservationStatusUpdate: @dataclass class ReserveNow: - status: str - status_info: Optional[Dict] = None + status: enums.ReserveNowStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class Reset: - status: str - status_info: Optional[Dict] = None + status: enums.ResetStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -323,62 +325,62 @@ class SecurityEventNotification: @dataclass class SendLocalList: - status: str - status_info: Optional[Dict] = None + status: enums.SendLocalListStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetChargingProfile: - status: str - status_info: Optional[Dict] = None + status: enums.ChargingProfileStatus + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetDisplayMessage: - status: str - status_info: Optional[Dict] = None + status: enums.DisplayMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringBase: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringLevel: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetNetworkProfile: - status: str - status_info: Optional[Dict] = None + status: enums.SetNetworkProfileStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariableMonitoring: - set_monitoring_result: List + set_monitoring_result: List[datatypes.SetMonitoringResultType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SetVariables: - set_variable_result: List + set_variable_result: List[datatypes.SetVariableResultType] custom_data: Optional[Dict[str, Any]] = None @dataclass class SignCertificate: - status: str - status_info: Optional[Dict] = None + status: enums.GenericStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -391,35 +393,35 @@ class StatusNotification: class TransactionEvent: total_cost: Optional[float] = None charging_priority: Optional[int] = None - id_token_info: Optional[Dict] = None - updated_personal_message: Optional[Dict] = None + id_token_info: Optional[datatypes.IdTokenInfoType] = None + updated_personal_message: Optional[datatypes.MessageContentType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class TriggerMessage: - status: str - status_info: Optional[Dict] = None + status: enums.TriggerMessageStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnlockConnector: - status: str - status_info: Optional[Dict] = None + status: enums.UnlockStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnpublishFirmware: - status: str + status: enums.UnpublishFirmwareStatusType custom_data: Optional[Dict[str, Any]] = None @dataclass class UpdateFirmware: - status: str - status_info: Optional[Dict] = None + status: enums.FirmwareStatusType + status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 1a63ba43f..cc03fc31b 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[str] = None + unit: Optional[enums.UnitOfMeasureType] = None multiplier: Optional[int] = None From fbe0c4988326f00298f90da68e8b3435de78a15c Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Fri, 22 Nov 2024 08:06:49 -0500 Subject: [PATCH 13/27] fixing linting errors --- ocpp/v201/call.py | 4 ++-- ocpp/v201/call_result.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ocpp/v201/call.py b/ocpp/v201/call.py index 34218d9b9..0f60762b5 100644 --- a/ocpp/v201/call.py +++ b/ocpp/v201/call.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional -from ocpp.v201 import enums -from ocpp.v201 import datatypes +from ocpp.v201 import datatypes, enums + @dataclass class Authorize: diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index d9aeeed3b..006001715 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -2,8 +2,8 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional -from ocpp.v201 import enums -from ocpp.v201 import datatypes +from ocpp.v201 import datatypes, enums + @dataclass class Authorize: @@ -155,7 +155,9 @@ class GetDisplayMessages: class GetInstalledCertificateIds: status: enums.GetInstalledCertificateStatusType status_info: Optional[datatypes.StatusInfoType] = None - certificate_hash_data_chain: Optional[List[datatypes.CertificateHashDataChainType]] = None + certificate_hash_data_chain: Optional[ + List[datatypes.CertificateHashDataChainType] + ] = None custom_data: Optional[Dict[str, Any]] = None From c3a96382d8ab82007580111c5ba5e4eb94c3f8f5 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Fri, 22 Nov 2024 09:01:15 -0500 Subject: [PATCH 14/27] Add code of conduct, contributing, security and support docs. Also includes a pull request template. Contributes to https://github.com/mobilityhouse/ocpp/issues/671 --- .github/pull_request_template.md | 21 +++++++++ CODE_OF_CONDUCT.md | 74 ++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 41 ++++++++++++++++++ SECURITY.md | 33 ++++++++++++++ SUPPORT.md | 34 +++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 SUPPORT.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..2e8477f4b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +### Changes included in this PR + +*(Bug fix, feature, docs update, ...)* + +### Current behavior + +*Link to an open issue here...* + +### New behavior + +*If this is a feature change, describe the new behavior* + +### Impact + +*Describe breaking changes, including changes a users might need to make due to this PR* + +### Checklist + +1. [ ] Does your submission pass the existing tests? +2. [ ] Are there new tests that cover these additions/changes? +3. [ ] Have you linted your code locally before submission? diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..86a391351 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at {{ email }}. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..b0037efe8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +## Contributing + +[fork]: /fork +[pr]: /compare +[style]: https://standardjs.com/ +[code-of-conduct]: CODE_OF_CONDUCT.md + +Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. + +Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. + +## Issues and PRs + +If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them. + +We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR. + +Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you. + +## Submitting a pull request + +1. [Fork][fork] and clone the repository. +1. Create a new branch: `git checkout -b my-branch-name`. +1. Configure and install the dependencies: `poetry install`. +1. Make sure the tests pass on your machine: `make install & make tests` +1. Make your change, add tests, and make sure the tests still pass. +1. Push to your fork and [submit a pull request][pr] and complete the information in the pull request template. + +## Linting requirements + +using `make install & make tests` will also run the following linters: + +- [Black: The uncompromising Python code formatter](https://black.readthedocs.io/en/stable/) +- [isort your imports, so you don't have to](https://pycqa.github.io/isort/) +- [flake8: Your Tool For Style Guide Enforcement](https://flake8.pycqa.org/en/latest/) + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) +- [GitHub Help](https://help.github.com) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..bd76a0f69 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,33 @@ +# Security Policy + +This document outlines security procedures and general policies for this OCPP project. + +## Supported Versions + +The currently supported versions of this OCPP project are: + +| Version | Supported | +|----------| ------------------ | +| 2.0.0 | :white_check_mark: | +| 0.26.0 | :white_check_mark: | +| < 0.26.0 | :x: | + +## Reporting a Vulnerability + +Please include the requested information listed below (as much as you can provide) to help +us better understand the nature and scope of the possible issue: + +- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) +- Full paths of source file(s) related to the manifestation of the issue +- The location of the affected source code (tag/branch/commit or direct URL) +- Any special configuration required to reproduce the issue +- Step-by-step instructions to reproduce the issue +- Proof-of-concept or exploit code (if possible) +- Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. Thanks! diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..72b64a6c6 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,34 @@ +# Support + +This article explains where to get help with this OCPP project. +Please read through the following guidelines. + +> 👉 **Note**: before participating in our community, please read our +> [code of conduct][coc]. +> By interacting with this repository, organization, or community you agree to +> abide by its terms. + +## Asking quality questions + +Questions can go to [GitHub discussions][chat]. + +Help us help you! +Spend time framing questions and add links and resources. +Spending the extra time up front can help save everyone time in the long run. +Here are some tips: + +* Search to find out if a similar question has been asked or a similar issue has been reported +* Check to see if a PR is already in progress for the issue you want to raise +* Try to define what you need help with: + * Is there something in particular you want to do? + * What problem are you encountering and what steps have you taken to try + and fix it? + * Is there a concept you don’t understand? +* Provide sample code, such as a [CodeSandbox][cs] or video, if possible +* Screenshots can help, but if there’s important text such as code or error + messages in them, please also provide those as text +* The more time you put into asking your question, the better we can help you + +## Contributions + +See [`contributing.md`][contributing] on how to contribute. From cd0a6a3630f562461d02257281400720e8d15665 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 21:22:22 -0500 Subject: [PATCH 15/27] adding unit tests for all the v201 data types to make sure they rehydrate the same as before. the enums and datatypes had an overlapping dataclass, both called UnitOfMeasureType. changed the enum to UnitOfMeasureUnitType. --- ocpp/v201/datatypes.py | 2 +- ocpp/v201/enums.py | 2 +- tests/v201/test_v201_data_types.py | 914 +++++++++++++++++++++++++++++ 3 files changed, 916 insertions(+), 2 deletions(-) create mode 100644 tests/v201/test_v201_data_types.py diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index cc03fc31b..27bb43af0 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.UnitOfMeasureType] = None + unit: Optional[enums.UnitOfMeasureUnitType] = None multiplier: Optional[int] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2f903ca75..2c69e953b 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureType(StrEnum): +class UnitOfMeasureUnitType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py new file mode 100644 index 000000000..570c8e186 --- /dev/null +++ b/tests/v201/test_v201_data_types.py @@ -0,0 +1,914 @@ +import json +from dataclasses import asdict +from typing import TypeVar + +from ocpp.v201.datatypes import * +from ocpp.v201.enums import ( + APNAuthenticationType, AttributeType, ChargingProfileKindType, + ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, + EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, + MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, + OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, + ReasonType, SetMonitoringStatusType, SetVariableStatusType, + UnitOfMeasureUnitType, VPNType +) + +T = TypeVar('T', bound='dataclass') + + +def to_datatype(cls, dc: T): + to_dict = asdict(dc) + to_json = json.dumps(to_dict) + from_json = json.loads(to_json) + return cls(**from_json) + + +def test_ac_charging_parameters_type(): + acpt = ACChargingParametersType( + energy_amount=20.5, + ev_min_current=10.0, + ev_max_current=32.0, + ev_max_voltage=400 + ) + + new_acpt = to_datatype(ACChargingParametersType, acpt) + + assert new_acpt.energy_amount == acpt.energy_amount + assert new_acpt.ev_min_current == acpt.ev_min_current + assert new_acpt.ev_max_current == acpt.ev_max_current + assert new_acpt.ev_max_voltage == acpt.ev_max_voltage + + +def test_additional_info_type(): + ait = AdditionalInfoType( + additional_id_token="additional_token123", + type="type_value" + ) + + new_ait = to_datatype(AdditionalInfoType, ait) + + assert new_ait.additional_id_token == ait.additional_id_token + assert new_ait.type == ait.type + + +def test_apn_type(): + at = APNType( + apn="internet.example.com", + apn_authentication="AUTO", + apn_user_name="username", + apn_password="password", + sim_pin=1234, + preferred_network="preferred", + use_only_preferred_network=True + ) + + new_at = to_datatype(APNType, at) + + assert new_at.apn == at.apn + assert new_at.apn_authentication == at.apn_authentication + assert new_at.apn_user_name == at.apn_user_name + assert new_at.apn_password == at.apn_password + assert new_at.sim_pin == at.sim_pin + assert new_at.preferred_network == at.preferred_network + assert new_at.use_only_preferred_network == at.use_only_preferred_network + + +def test_authorization_data(): + ad = AuthorizationData( + id_token_info=IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr" + ), + id_token=IdTokenType.iso14443 + ) + + new_ad = to_datatype(AuthorizationData, ad) + + assert isinstance(new_ad.id_token_info, dict) + assert new_ad.id_token_info['status'] == ad.id_token_info.status + assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time + assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority + assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 + assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert isinstance(new_ad.id_token, str) + assert new_ad.id_token == ad.id_token + + +def test_certificate_hash_data_chain_type(): + chdct = CertificateHashDataChainType( + certificate_type="V2G", + certificate_hash_data=CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ), + child_certificate_hash_data=[ + CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="child_issuer_hash", + issuer_key_hash="child_key_hash", + serial_number="child_serial123" + ) + ] + ) + + new_chdct = to_datatype(CertificateHashDataChainType, chdct) + + assert new_chdct.certificate_type == chdct.certificate_type + assert isinstance(new_chdct.certificate_hash_data, dict) + assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm + assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash + assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash + assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert isinstance(new_chdct.child_certificate_hash_data[0], dict) + assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + + +def test_certificate_hash_data_type(): + chdt = CertificateHashDataType( + hash_algorithm="SHA256", + issuer_name_hash="issuer_hash", + issuer_key_hash="key_hash", + serial_number="serial123" + ) + + new_chdt = to_datatype(CertificateHashDataType, chdt) + + assert new_chdt.hash_algorithm == chdt.hash_algorithm + assert new_chdt.issuer_name_hash == chdt.issuer_name_hash + assert new_chdt.issuer_key_hash == chdt.issuer_key_hash + assert new_chdt.serial_number == chdt.serial_number + + +def test_charging_limit_type(): + clt = ChargingLimitType( + charging_limit_source="EMS", + is_grid_critical=True + ) + + new_clt = to_datatype(ChargingLimitType, clt) + + assert new_clt.charging_limit_source == clt.charging_limit_source + assert new_clt.is_grid_critical == clt.is_grid_critical + + +def test_charging_needs_type(): + cnt = ChargingNeedsType( + requested_energy_transfer=EnergyTransferModeType.dc, + departure_time="2024-01-01T10:00:00Z", + ac_charging_parameters=ACChargingParametersType( + energy_amount=20, + ev_min_current=10, + ev_max_current=32, + ev_max_voltage=400 + ), + dc_charging_parameters=DCChargingParametersType( + ev_max_current=100, + ev_max_voltage=500, + energy_amount=50, + ev_max_power=50000, + state_of_charge=80 + ) + ) + + new_cnt = to_datatype(ChargingNeedsType, cnt) + + assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer + assert new_cnt.departure_time == cnt.departure_time + assert isinstance(new_cnt.ac_charging_parameters, dict) + assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount + assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert isinstance(new_cnt.dc_charging_parameters, dict) + assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current + assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + + +def test_charging_profile_criterion_type(): + cpct = ChargingProfileCriterionType( + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0, + charging_profile_id=[1, 2, 3] + ) + + new_cpct = to_datatype(ChargingProfileCriterionType, cpct) + + assert new_cpct.charging_profile_purpose == cpct.charging_profile_purpose + assert new_cpct.stack_level == cpct.stack_level + assert new_cpct.charging_profile_id == cpct.charging_profile_id + + +def test_charging_profile_type(): + cpt = ChargingProfileType( + id=1, + stack_level=0, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + charging_profile_kind=ChargingProfileKindType.absolute, + charging_schedule=[ + ChargingScheduleType( + id=1, + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ], + start_schedule="2024-01-01T10:00:00Z", + duration=3600 + ) + ], + valid_from="2024-01-01T00:00:00Z", + valid_to="2024-12-31T23:59:59Z" + ) + + new_cpt = to_datatype(ChargingProfileType, cpt) + + assert new_cpt.id == cpt.id + assert new_cpt.stack_level == cpt.stack_level + assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose + assert new_cpt.charging_profile_kind == cpt.charging_profile_kind + assert isinstance(new_cpt.charging_schedule[0], dict) + assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.valid_from == cpt.valid_from + assert new_cpt.valid_to == cpt.valid_to + + +def test_charging_schedule_period_type(): + cspt = ChargingSchedulePeriodType( + start_period=0, + limit=32.0, + number_phases=3, + phase_to_use=1 + ) + + new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) + + assert new_cspt.start_period == cspt.start_period + assert new_cspt.limit == cspt.limit + assert new_cspt.number_phases == cspt.number_phases + assert new_cspt.phase_to_use == cspt.phase_to_use + + +def test_charging_station_type(): + cst = ChargingStationType( + model="Station Model X", + vendor_name="Vendor ABC", + serial_number="SN123456", + modem=ModemType( + iccid="89001234567890123456", + imsi="123456789012345" + ), + firmware_version="1.2.3" + ) + + new_cst = to_datatype(ChargingStationType, cst) + + assert new_cst.model == cst.model + assert new_cst.vendor_name == cst.vendor_name + assert new_cst.serial_number == cst.serial_number + assert isinstance(new_cst.modem, dict) + assert new_cst.modem['iccid'] == cst.modem.iccid + assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.firmware_version == cst.firmware_version + + +def test_clear_charging_profile_type(): + ccpt = ClearChargingProfileType( + evse_id=1, + charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + stack_level=0 + ) + + new_ccpt = to_datatype(ClearChargingProfileType, ccpt) + + assert new_ccpt.evse_id == ccpt.evse_id + assert new_ccpt.charging_profile_purpose == ccpt.charging_profile_purpose + assert new_ccpt.stack_level == ccpt.stack_level + + +def test_clear_monitoring_result_type(): + cmrt = ClearMonitoringResultType( + status="Accepted", + id=123, + status_info=StatusInfoType( + reason_code="Cleared", + additional_info="Successfully cleared monitoring" + ) + ) + + new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) + + assert new_cmrt.status == cmrt.status + assert new_cmrt.id == cmrt.id + assert isinstance(new_cmrt.status_info, dict) + assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code + assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + + +def test_component_type(): + ct = ComponentType( + name="MainController", + instance="instance1", + evse=EVSEType( + id=1, + connector_id=2 + ) + ) + + new_ct = to_datatype(ComponentType, ct) + + assert new_ct.name == ct.name + assert new_ct.instance == ct.instance + assert isinstance(new_ct.evse, dict) + assert new_ct.evse['id'] == ct.evse.id + assert new_ct.evse['connector_id'] == ct.evse.connector_id + + +def test_component_variable_type(): + cvt = ComponentVariableType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_cvt = to_datatype(ComponentVariableType, cvt) + + assert isinstance(new_cvt.component, dict) + assert new_cvt.component['name'] == cvt.component.name + assert new_cvt.component['instance'] == cvt.component.instance + assert isinstance(new_cvt.variable, dict) + assert new_cvt.variable['name'] == cvt.variable.name + assert new_cvt.variable['instance'] == cvt.variable.instance + + +def test_composite_schedule_type(): + cst = CompositeScheduleType( + evse_id=1, + duration=3600, + schedule_start="2024-01-01T10:00:00Z", + charging_rate_unit=ChargingRateUnitType.watts, + charging_schedule_period=[ + ChargingSchedulePeriodType( + start_period=0, + limit=11000.0, + number_phases=3 + ) + ] + ) + + new_cst = to_datatype(CompositeScheduleType, cst) + + assert new_cst.evse_id == cst.evse_id + assert new_cst.duration == cst.duration + assert new_cst.schedule_start == cst.schedule_start + assert new_cst.charging_rate_unit == cst.charging_rate_unit + assert isinstance(new_cst.charging_schedule_period[0], dict) + assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period + assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + + +def test_consumption_cost_type(): + cct = ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + + new_cct = to_datatype(ConsumptionCostType, cct) + + assert new_cct.start_value == cct.start_value + assert isinstance(new_cct.cost[0], dict) + assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind + assert new_cct.cost[0]['amount'] == cct.cost[0].amount + assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + + +def test_cost_type(): + ct = CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + + new_ct = to_datatype(CostType, ct) + + assert new_ct.cost_kind == ct.cost_kind + assert new_ct.amount == ct.amount + assert new_ct.amount_multiplier == ct.amount_multiplier + + +def test_event_data_type(): + edt = EventDataType( + event_id=1, + timestamp="2024-01-01T10:00:00Z", + trigger="Alerting", + actual_value="High Temperature", + tech_code="TC001", + tech_info="Temperature sensor reading high", + cleared=False, + transaction_id="TX001", + variable_monitoring_id=1, + event_notification_type="HardWiredNotification", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ) + ) + + new_edt = to_datatype(EventDataType, edt) + + assert new_edt.event_id == edt.event_id + assert new_edt.timestamp == edt.timestamp + assert new_edt.trigger == edt.trigger + assert new_edt.actual_value == edt.actual_value + assert new_edt.tech_code == edt.tech_code + assert new_edt.tech_info == edt.tech_info + assert new_edt.cleared == edt.cleared + assert new_edt.transaction_id == edt.transaction_id + assert new_edt.variable_monitoring_id == edt.variable_monitoring_id + assert new_edt.event_notification_type == edt.event_notification_type + assert isinstance(new_edt.component, dict) + assert new_edt.component['name'] == edt.component.name + assert isinstance(new_edt.variable, dict) + assert new_edt.variable['name'] == edt.variable.name + + +def test_firmware_type(): + ft = FirmwareType( + location="https://firmware.example.com/v1.2.3", + retrieve_date_time="2024-01-01T10:00:00Z", + install_date_time="2024-01-01T11:00:00Z", + signing_certificate="MIIB...", + signature="SHA256..." + ) + + new_ft = to_datatype(FirmwareType, ft) + + assert new_ft.location == ft.location + assert new_ft.retrieve_date_time == ft.retrieve_date_time + assert new_ft.install_date_time == ft.install_date_time + assert new_ft.signing_certificate == ft.signing_certificate + assert new_ft.signature == ft.signature + + +def test_get_variable_data_type(): + gvdt = GetVariableDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ), + attribute_type=AttributeType.actual + ) + + new_gvdt = to_datatype(GetVariableDataType, gvdt) + + assert isinstance(new_gvdt.component, dict) + assert new_gvdt.component['name'] == gvdt.component.name + assert new_gvdt.component['instance'] == gvdt.component.instance + assert isinstance(new_gvdt.variable, dict) + assert new_gvdt.variable['name'] == gvdt.variable.name + assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.attribute_type == gvdt.attribute_type + + +def test_get_variable_result_type(): + gvrt = GetVariableResultType( + attribute_status="Accepted", + attribute_type=AttributeType.actual, + attribute_value="100", + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="CurrentLimit", + instance="instance1" + ) + ) + + new_gvrt = to_datatype(GetVariableResultType, gvrt) + + assert new_gvrt.attribute_status == gvrt.attribute_status + assert new_gvrt.attribute_type == gvrt.attribute_type + assert new_gvrt.attribute_value == gvrt.attribute_value + assert isinstance(new_gvrt.component, dict) + assert new_gvrt.component['name'] == gvrt.component.name + assert isinstance(new_gvrt.variable, dict) + assert new_gvrt.variable['name'] == gvrt.variable.name + + +def test_id_token_info_type(): + itit = IdTokenInfoType( + status="Accepted", + cache_expiry_date_time="2024-01-01T10:00:00Z", + charging_priority=1, + language_1="en", + language_2="fr", + group_id_token=IdTokenType.central, + personal_message=MessageContentType( + format=MessageFormatType.ascii, + content="Welcome back!", + language="en" + ) + ) + + new_itit = to_datatype(IdTokenInfoType, itit) + + assert new_itit.status == itit.status + assert new_itit.cache_expiry_date_time == itit.cache_expiry_date_time + assert new_itit.charging_priority == itit.charging_priority + assert new_itit.language_1 == itit.language_1 + assert new_itit.language_2 == itit.language_2 + assert isinstance(new_itit.group_id_token, str) + assert new_itit.group_id_token == itit.group_id_token + assert isinstance(new_itit.personal_message, dict) + assert new_itit.personal_message['content'] == itit.personal_message.content + + +def test_log_parameters_type(): + lpt = LogParametersType( + remote_location="https://logs.example.com", + oldest_timestamp="2024-01-01T00:00:00Z", + latest_timestamp="2024-01-01T23:59:59Z" + ) + + new_lpt = to_datatype(LogParametersType, lpt) + + assert new_lpt.remote_location == lpt.remote_location + assert new_lpt.oldest_timestamp == lpt.oldest_timestamp + assert new_lpt.latest_timestamp == lpt.latest_timestamp + + +def test_message_info_type(): + mit = MessageInfoType( + id=1, + priority=1, + message=MessageContentType( + format=MessageFormatType.ascii, + content="Important notice", + language="en" + ), + display=ComponentType( + name="MainDisplay", + instance="instance1" + ), + state="Charging" + ) + + new_mit = to_datatype(MessageInfoType, mit) + + assert new_mit.id == mit.id + assert new_mit.priority == mit.priority + assert isinstance(new_mit.message, dict) + assert new_mit.message['content'] == mit.message.content + assert isinstance(new_mit.display, dict) + assert new_mit.display['name'] == mit.display.name + assert new_mit.state == mit.state + + +def test_meter_value_type(): + mvt = MeterValueType( + timestamp="2024-01-01T10:00:00Z", + sampled_value=[ + SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet + ) + ] + ) + + new_mvt = to_datatype(MeterValueType, mvt) + + assert new_mvt.timestamp == mvt.timestamp + assert isinstance(new_mvt.sampled_value[0], dict) + assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + + +def test_modem_type(): + mt = ModemType( + iccid="89012345678901234567", + imsi="123456789012345" + ) + + new_mt = to_datatype(ModemType, mt) + + assert new_mt.iccid == mt.iccid + assert new_mt.imsi == mt.imsi + + +def test_monitoring_data_type(): + mdt = MonitoringDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_monitoring=VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + ) + + new_mdt = to_datatype(MonitoringDataType, mdt) + + assert isinstance(new_mdt.component, dict) + assert new_mdt.component['name'] == mdt.component.name + assert isinstance(new_mdt.variable, dict) + assert new_mdt.variable['name'] == mdt.variable.name + assert isinstance(new_mdt.variable_monitoring, dict) + assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + + +def test_network_connection_profile_type(): + ncpt = NetworkConnectionProfileType( + ocpp_version=OCPPVersionType.ocpp20, + ocpp_transport=OCPPTransportType.json, + ocpp_csms_url="wss://example.com/ocpp", + message_timeout=30, + security_profile=1, + ocpp_interface=OCPPInterfaceType.wired0 + ) + + new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) + + assert new_ncpt.ocpp_version == ncpt.ocpp_version + assert new_ncpt.ocpp_transport == ncpt.ocpp_transport + assert new_ncpt.ocpp_csms_url == ncpt.ocpp_csms_url + assert new_ncpt.message_timeout == ncpt.message_timeout + assert new_ncpt.security_profile == ncpt.security_profile + assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + + +def test_ocsp_request_data_type(): + ordt = OCSPRequestDataType( + hash_algorithm=HashAlgorithmType.sha256, + issuer_name_hash="issuer_hash_value", + issuer_key_hash="issuer_key_hash_value", + serial_number="serial123", + responder_url="http://ocsp.example.com" + ) + + new_ordt = to_datatype(OCSPRequestDataType, ordt) + + assert new_ordt.hash_algorithm == ordt.hash_algorithm + assert new_ordt.issuer_name_hash == ordt.issuer_name_hash + assert new_ordt.issuer_key_hash == ordt.issuer_key_hash + assert new_ordt.serial_number == ordt.serial_number + assert new_ordt.responder_url == ordt.responder_url + + +def test_relative_time_interval_type(): + rtit = RelativeTimeIntervalType( + start=0, + duration=3600 + ) + + new_rtit = to_datatype(RelativeTimeIntervalType, rtit) + + assert new_rtit.start == rtit.start + assert new_rtit.duration == rtit.duration + + +def test_report_data_type(): + rdt = ReportDataType( + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + variable_attribute=[ + VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + ], + variable_characteristics=VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + ) + + new_rdt = to_datatype(ReportDataType, rdt) + + assert isinstance(new_rdt.component, dict) + assert new_rdt.component['name'] == rdt.component.name + assert isinstance(new_rdt.variable, dict) + assert new_rdt.variable['name'] == rdt.variable.name + assert isinstance(new_rdt.variable_attribute[0], dict) + assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert isinstance(new_rdt.variable_characteristics, dict) + assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit + assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type + assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + + +def test_sales_tariff_entry_type(): + stet = SalesTariffEntryType( + e_price_level=1, + relative_time_interval=RelativeTimeIntervalType( + start=0, + duration=3600 + ), + consumption_cost=[ + ConsumptionCostType( + start_value=0.0, + cost=[ + CostType( + cost_kind="RelativePrice", + amount=1.0, + amount_multiplier=0 + ) + ] + ) + ] + ) + + new_stet = to_datatype(SalesTariffEntryType, stet) + + assert new_stet.e_price_level == stet.e_price_level + assert isinstance(new_stet.relative_time_interval, dict) + assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start + assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert isinstance(new_stet.consumption_cost[0], dict) + assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value + assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) + assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind + assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount + assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + + +def test_sampled_value_type(): + svt = SampledValueType( + value=230.0, + context=ReadingContextType.sample_periodic, + measurand=MeasurandType.voltage, + phase=PhaseType.l1, + location=LocationType.outlet, + unit_of_measure=UnitOfMeasureType( + unit=UnitOfMeasureUnitType.v, + multiplier=0 + ) + ) + + new_svt = to_datatype(SampledValueType, svt) + + assert new_svt.value == svt.value + assert new_svt.context == svt.context + assert new_svt.measurand == svt.measurand + assert new_svt.phase == svt.phase + assert new_svt.location == svt.location + assert isinstance(new_svt.unit_of_measure, dict) + assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + + +def test_set_monitoring_data_type(): + smdt = SetMonitoringDataType( + value=100.0, + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType( + name="MainController", + instance="instance1" + ), + variable=VariableType( + name="Temperature", + instance="instance1" + ), + id=123456 + ) + + new_smdt = to_datatype(SetMonitoringDataType, smdt) + + assert new_smdt.value == smdt.value + assert new_smdt.type == smdt.type + assert new_smdt.severity == smdt.severity + assert isinstance(new_smdt.component, dict) + assert new_smdt.component['name'] == smdt.component.name + assert new_smdt.component['instance'] == smdt.component.instance + assert isinstance(new_smdt.variable, dict) + assert new_smdt.variable['name'] == smdt.variable.name + assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.id == smdt.id + + +def test_unit_of_measure_type(): + uomt = UnitOfMeasureType( + #unit=UnitOfMeasureType.w, + multiplier=1 + ) + + new_uomt = to_datatype(UnitOfMeasureType, uomt) + + assert new_uomt.unit == uomt.unit + assert new_uomt.multiplier == uomt.multiplier + + +def test_variable_attribute_type(): + vat = VariableAttributeType( + type=AttributeType.actual, + value="25.5", + mutability="ReadWrite", + persistent=True, + constant=False + ) + + new_vat = to_datatype(VariableAttributeType, vat) + + assert new_vat.type == vat.type + assert new_vat.value == vat.value + assert new_vat.mutability == vat.mutability + assert new_vat.persistent == vat.persistent + assert new_vat.constant == vat.constant + + +def test_variable_characteristics_type(): + vct = VariableCharacteristicsType( + unit="Celsius", + data_type="decimal", + min_limit="-20", + max_limit="50", + values_list=["10", "20", "30"], + supports_monitoring=True + ) + + new_vct = to_datatype(VariableCharacteristicsType, vct) + + assert new_vct.unit == vct.unit + assert new_vct.data_type == vct.data_type + assert new_vct.min_limit == vct.min_limit + assert new_vct.max_limit == vct.max_limit + assert new_vct.values_list == vct.values_list + assert new_vct.supports_monitoring == vct.supports_monitoring + + +def test_variable_monitoring_type(): + vmt = VariableMonitoringType( + id=1, + transaction=True, + value=100.0, + type=MonitorType.upper_threshold, + severity=1 + ) + + new_vmt = to_datatype(VariableMonitoringType, vmt) + + assert new_vmt.id == vmt.id + assert new_vmt.transaction == vmt.transaction + assert new_vmt.value == vmt.value + assert new_vmt.type == vmt.type + assert new_vmt.severity == vmt.severity + + + + + + From e0ba5f5f3e64075283ae9f0a02ea307270a1c011 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:16:41 -0500 Subject: [PATCH 16/27] fixing formatting, import sorting and make sure all imports are being used --- ocpp/v201/datatypes.py | 4 +- ocpp/v201/enums.py | 4 +- tests/v201/test_v201_data_types.py | 628 +++++++++++++++++------------ 3 files changed, 366 insertions(+), 270 deletions(-) diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 27bb43af0..59c80b24c 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -454,7 +454,7 @@ class IdTokenType: """ id_token: str - type: enums.IdTokenType + type: enums.IdTokenEnumType additional_info: Optional[List[AdditionalInfoType]] = None @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.UnitOfMeasureUnitType] = None + unit: Optional[enums.StandardizedUnitsOfMeasureType] = None multiplier: Optional[int] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 2c69e953b..421553890 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -721,7 +721,7 @@ class HashAlgorithmType(StrEnum): sha512 = "SHA512" -class IdTokenType(StrEnum): +class IdTokenEnumType(StrEnum): """ Allowable values of the IdTokenType field. """ @@ -1321,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class UnitOfMeasureUnitType(StrEnum): +class StandardizedUnitsOfMeasureType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 570c8e186..4fe65a15e 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -1,19 +1,92 @@ import json -from dataclasses import asdict +from dataclasses import asdict, dataclass from typing import TypeVar -from ocpp.v201.datatypes import * +from ocpp.v201.datatypes import ( + ACChargingParametersType, + AdditionalInfoType, + APNType, + AuthorizationData, + CertificateHashDataChainType, + CertificateHashDataType, + ChargingLimitType, + ChargingNeedsType, + ChargingProfileCriterionType, + ChargingProfileType, + ChargingSchedulePeriodType, + ChargingScheduleType, + ChargingStationType, + ClearChargingProfileType, + ClearMonitoringResultType, + ComponentType, + ComponentVariableType, + CompositeScheduleType, + ConsumptionCostType, + CostType, + DCChargingParametersType, + EventDataType, + EVSEType, + FirmwareType, + GetVariableDataType, + GetVariableResultType, + IdTokenInfoType, + IdTokenType, + LogParametersType, + MessageContentType, + MessageInfoType, + MeterValueType, + ModemType, + MonitoringDataType, + NetworkConnectionProfileType, + OCSPRequestDataType, + RelativeTimeIntervalType, + ReportDataType, + SalesTariffEntryType, + SampledValueType, + SetMonitoringDataType, + SetMonitoringResultType, + SetVariableResultType, + StatusInfoType, + UnitOfMeasureType, + VariableAttributeType, + VariableCharacteristicsType, + VariableMonitoringType, + VariableType, +) from ocpp.v201.enums import ( - APNAuthenticationType, AttributeType, ChargingProfileKindType, - ChargingProfilePurposeType, ChargingRateUnitType, ChargingStateType, - EnergyTransferModeType, HashAlgorithmType, IdTokenType, LocationType, - MessageFormatType, MeasurandType, MonitorType, OCPPInterfaceType, - OCPPTransportType, OCPPVersionType, PhaseType, ReadingContextType, - ReasonType, SetMonitoringStatusType, SetVariableStatusType, - UnitOfMeasureUnitType, VPNType + APNAuthenticationType, + AttributeType, + AuthorizationStatusType, + ChargingProfileKindType, + ChargingProfilePurposeType, + ChargingRateUnitType, + ChargingStateType, + ClearMonitoringStatusType, + CostKindType, + DataType, + EnergyTransferModeType, + EventNotificationType, + EventTriggerType, + HashAlgorithmType, + IdTokenEnumType, + LocationType, + MeasurandType, + MessageFormatType, + MonitorType, + MutabilityType, + OCPPInterfaceType, + OCPPTransportType, + OCPPVersionType, + PhaseType, + ReadingContextType, + ReasonType, + SetMonitoringStatusType, + SetVariableStatusType, + StandardizedUnitsOfMeasureType, + VPNType, ) -T = TypeVar('T', bound='dataclass') +T = TypeVar("T", bound="dataclass") def to_datatype(cls, dc: T): @@ -25,10 +98,7 @@ def to_datatype(cls, dc: T): def test_ac_charging_parameters_type(): acpt = ACChargingParametersType( - energy_amount=20.5, - ev_min_current=10.0, - ev_max_current=32.0, - ev_max_voltage=400 + energy_amount=20.5, ev_min_current=10.0, ev_max_current=32.0, ev_max_voltage=400 ) new_acpt = to_datatype(ACChargingParametersType, acpt) @@ -41,8 +111,7 @@ def test_ac_charging_parameters_type(): def test_additional_info_type(): ait = AdditionalInfoType( - additional_id_token="additional_token123", - type="type_value" + additional_id_token="additional_token123", type="type_value" ) new_ait = to_datatype(AdditionalInfoType, ait) @@ -54,12 +123,12 @@ def test_additional_info_type(): def test_apn_type(): at = APNType( apn="internet.example.com", - apn_authentication="AUTO", + apn_authentication=APNAuthenticationType.auto, apn_user_name="username", apn_password="password", sim_pin=1234, preferred_network="preferred", - use_only_preferred_network=True + use_only_preferred_network=True, ) new_at = to_datatype(APNType, at) @@ -76,23 +145,32 @@ def test_apn_type(): def test_authorization_data(): ad = AuthorizationData( id_token_info=IdTokenInfoType( - status="Accepted", + status=AuthorizationStatusType.accepted, cache_expiry_date_time="2024-01-01T10:00:00Z", charging_priority=1, language_1="en", - language_2="fr" + language_2="fr", + group_id_token=IdTokenType( + type=IdTokenEnumType.central, + id_token="1234567890", + ), ), - id_token=IdTokenType.iso14443 + id_token=IdTokenEnumType.central, ) new_ad = to_datatype(AuthorizationData, ad) assert isinstance(new_ad.id_token_info, dict) - assert new_ad.id_token_info['status'] == ad.id_token_info.status - assert new_ad.id_token_info['cache_expiry_date_time'] == ad.id_token_info.cache_expiry_date_time - assert new_ad.id_token_info['charging_priority'] == ad.id_token_info.charging_priority - assert new_ad.id_token_info['language_1'] == ad.id_token_info.language_1 - assert new_ad.id_token_info['language_2'] == ad.id_token_info.language_2 + assert new_ad.id_token_info["status"] == ad.id_token_info.status + assert ( + new_ad.id_token_info["cache_expiry_date_time"] + == ad.id_token_info.cache_expiry_date_time + ) + assert ( + new_ad.id_token_info["charging_priority"] == ad.id_token_info.charging_priority + ) + assert new_ad.id_token_info["language_1"] == ad.id_token_info.language_1 + assert new_ad.id_token_info["language_2"] == ad.id_token_info.language_2 assert isinstance(new_ad.id_token, str) assert new_ad.id_token == ad.id_token @@ -104,28 +182,43 @@ def test_certificate_hash_data_chain_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ), child_certificate_hash_data=[ CertificateHashDataType( hash_algorithm="SHA256", issuer_name_hash="child_issuer_hash", issuer_key_hash="child_key_hash", - serial_number="child_serial123" + serial_number="child_serial123", ) - ] + ], ) new_chdct = to_datatype(CertificateHashDataChainType, chdct) assert new_chdct.certificate_type == chdct.certificate_type assert isinstance(new_chdct.certificate_hash_data, dict) - assert new_chdct.certificate_hash_data['hash_algorithm'] == chdct.certificate_hash_data.hash_algorithm - assert new_chdct.certificate_hash_data['issuer_name_hash'] == chdct.certificate_hash_data.issuer_name_hash - assert new_chdct.certificate_hash_data['issuer_key_hash'] == chdct.certificate_hash_data.issuer_key_hash - assert new_chdct.certificate_hash_data['serial_number'] == chdct.certificate_hash_data.serial_number + assert ( + new_chdct.certificate_hash_data["hash_algorithm"] + == chdct.certificate_hash_data.hash_algorithm + ) + assert ( + new_chdct.certificate_hash_data["issuer_name_hash"] + == chdct.certificate_hash_data.issuer_name_hash + ) + assert ( + new_chdct.certificate_hash_data["issuer_key_hash"] + == chdct.certificate_hash_data.issuer_key_hash + ) + assert ( + new_chdct.certificate_hash_data["serial_number"] + == chdct.certificate_hash_data.serial_number + ) assert isinstance(new_chdct.child_certificate_hash_data[0], dict) - assert new_chdct.child_certificate_hash_data[0]['hash_algorithm'] == chdct.child_certificate_hash_data[0].hash_algorithm + assert ( + new_chdct.child_certificate_hash_data[0]["hash_algorithm"] + == chdct.child_certificate_hash_data[0].hash_algorithm + ) def test_certificate_hash_data_type(): @@ -133,7 +226,7 @@ def test_certificate_hash_data_type(): hash_algorithm="SHA256", issuer_name_hash="issuer_hash", issuer_key_hash="key_hash", - serial_number="serial123" + serial_number="serial123", ) new_chdt = to_datatype(CertificateHashDataType, chdt) @@ -145,10 +238,7 @@ def test_certificate_hash_data_type(): def test_charging_limit_type(): - clt = ChargingLimitType( - charging_limit_source="EMS", - is_grid_critical=True - ) + clt = ChargingLimitType(charging_limit_source="EMS", is_grid_critical=True) new_clt = to_datatype(ChargingLimitType, clt) @@ -161,18 +251,15 @@ def test_charging_needs_type(): requested_energy_transfer=EnergyTransferModeType.dc, departure_time="2024-01-01T10:00:00Z", ac_charging_parameters=ACChargingParametersType( - energy_amount=20, - ev_min_current=10, - ev_max_current=32, - ev_max_voltage=400 + energy_amount=20, ev_min_current=10, ev_max_current=32, ev_max_voltage=400 ), dc_charging_parameters=DCChargingParametersType( ev_max_current=100, ev_max_voltage=500, energy_amount=50, ev_max_power=50000, - state_of_charge=80 - ) + state_of_charge=80, + ), ) new_cnt = to_datatype(ChargingNeedsType, cnt) @@ -180,18 +267,30 @@ def test_charging_needs_type(): assert new_cnt.requested_energy_transfer == cnt.requested_energy_transfer assert new_cnt.departure_time == cnt.departure_time assert isinstance(new_cnt.ac_charging_parameters, dict) - assert new_cnt.ac_charging_parameters['energy_amount'] == cnt.ac_charging_parameters.energy_amount - assert new_cnt.ac_charging_parameters['ev_min_current'] == cnt.ac_charging_parameters.ev_min_current + assert ( + new_cnt.ac_charging_parameters["energy_amount"] + == cnt.ac_charging_parameters.energy_amount + ) + assert ( + new_cnt.ac_charging_parameters["ev_min_current"] + == cnt.ac_charging_parameters.ev_min_current + ) assert isinstance(new_cnt.dc_charging_parameters, dict) - assert new_cnt.dc_charging_parameters['ev_max_current'] == cnt.dc_charging_parameters.ev_max_current - assert new_cnt.dc_charging_parameters['state_of_charge'] == cnt.dc_charging_parameters.state_of_charge + assert ( + new_cnt.dc_charging_parameters["ev_max_current"] + == cnt.dc_charging_parameters.ev_max_current + ) + assert ( + new_cnt.dc_charging_parameters["state_of_charge"] + == cnt.dc_charging_parameters.state_of_charge + ) def test_charging_profile_criterion_type(): cpct = ChargingProfileCriterionType( charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, stack_level=0, - charging_profile_id=[1, 2, 3] + charging_profile_id=[1, 2, 3], ) new_cpct = to_datatype(ChargingProfileCriterionType, cpct) @@ -213,17 +312,15 @@ def test_charging_profile_type(): charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 + start_period=0, limit=11000.0, number_phases=3 ) ], start_schedule="2024-01-01T10:00:00Z", - duration=3600 + duration=3600, ) ], valid_from="2024-01-01T00:00:00Z", - valid_to="2024-12-31T23:59:59Z" + valid_to="2024-12-31T23:59:59Z", ) new_cpt = to_datatype(ChargingProfileType, cpt) @@ -233,17 +330,14 @@ def test_charging_profile_type(): assert new_cpt.charging_profile_purpose == cpt.charging_profile_purpose assert new_cpt.charging_profile_kind == cpt.charging_profile_kind assert isinstance(new_cpt.charging_schedule[0], dict) - assert new_cpt.charging_schedule[0]['id'] == cpt.charging_schedule[0].id + assert new_cpt.charging_schedule[0]["id"] == cpt.charging_schedule[0].id assert new_cpt.valid_from == cpt.valid_from assert new_cpt.valid_to == cpt.valid_to def test_charging_schedule_period_type(): cspt = ChargingSchedulePeriodType( - start_period=0, - limit=32.0, - number_phases=3, - phase_to_use=1 + start_period=0, limit=32.0, number_phases=3, phase_to_use=1 ) new_cspt = to_datatype(ChargingSchedulePeriodType, cspt) @@ -259,11 +353,8 @@ def test_charging_station_type(): model="Station Model X", vendor_name="Vendor ABC", serial_number="SN123456", - modem=ModemType( - iccid="89001234567890123456", - imsi="123456789012345" - ), - firmware_version="1.2.3" + modem=ModemType(iccid="89001234567890123456", imsi="123456789012345"), + firmware_version="1.2.3", ) new_cst = to_datatype(ChargingStationType, cst) @@ -272,8 +363,8 @@ def test_charging_station_type(): assert new_cst.vendor_name == cst.vendor_name assert new_cst.serial_number == cst.serial_number assert isinstance(new_cst.modem, dict) - assert new_cst.modem['iccid'] == cst.modem.iccid - assert new_cst.modem['imsi'] == cst.modem.imsi + assert new_cst.modem["iccid"] == cst.modem.iccid + assert new_cst.modem["imsi"] == cst.modem.imsi assert new_cst.firmware_version == cst.firmware_version @@ -281,7 +372,7 @@ def test_clear_charging_profile_type(): ccpt = ClearChargingProfileType( evse_id=1, charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, - stack_level=0 + stack_level=0, ) new_ccpt = to_datatype(ClearChargingProfileType, ccpt) @@ -293,12 +384,12 @@ def test_clear_charging_profile_type(): def test_clear_monitoring_result_type(): cmrt = ClearMonitoringResultType( - status="Accepted", + status=ClearMonitoringStatusType.accepted, id=123, status_info=StatusInfoType( - reason_code="Cleared", - additional_info="Successfully cleared monitoring" - ) + reason_code=ReasonType.other, + additional_info="Successfully cleared monitoring", + ), ) new_cmrt = to_datatype(ClearMonitoringResultType, cmrt) @@ -306,18 +397,13 @@ def test_clear_monitoring_result_type(): assert new_cmrt.status == cmrt.status assert new_cmrt.id == cmrt.id assert isinstance(new_cmrt.status_info, dict) - assert new_cmrt.status_info['reason_code'] == cmrt.status_info.reason_code - assert new_cmrt.status_info['additional_info'] == cmrt.status_info.additional_info + assert new_cmrt.status_info["reason_code"] == cmrt.status_info.reason_code + assert new_cmrt.status_info["additional_info"] == cmrt.status_info.additional_info def test_component_type(): ct = ComponentType( - name="MainController", - instance="instance1", - evse=EVSEType( - id=1, - connector_id=2 - ) + name="MainController", instance="instance1", evse=EVSEType(id=1, connector_id=2) ) new_ct = to_datatype(ComponentType, ct) @@ -325,30 +411,24 @@ def test_component_type(): assert new_ct.name == ct.name assert new_ct.instance == ct.instance assert isinstance(new_ct.evse, dict) - assert new_ct.evse['id'] == ct.evse.id - assert new_ct.evse['connector_id'] == ct.evse.connector_id + assert new_ct.evse["id"] == ct.evse.id + assert new_ct.evse["connector_id"] == ct.evse.connector_id def test_component_variable_type(): cvt = ComponentVariableType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_cvt = to_datatype(ComponentVariableType, cvt) assert isinstance(new_cvt.component, dict) - assert new_cvt.component['name'] == cvt.component.name - assert new_cvt.component['instance'] == cvt.component.instance + assert new_cvt.component["name"] == cvt.component.name + assert new_cvt.component["instance"] == cvt.component.instance assert isinstance(new_cvt.variable, dict) - assert new_cvt.variable['name'] == cvt.variable.name - assert new_cvt.variable['instance'] == cvt.variable.instance + assert new_cvt.variable["name"] == cvt.variable.name + assert new_cvt.variable["instance"] == cvt.variable.instance def test_composite_schedule_type(): @@ -358,12 +438,8 @@ def test_composite_schedule_type(): schedule_start="2024-01-01T10:00:00Z", charging_rate_unit=ChargingRateUnitType.watts, charging_schedule_period=[ - ChargingSchedulePeriodType( - start_period=0, - limit=11000.0, - number_phases=3 - ) - ] + ChargingSchedulePeriodType(start_period=0, limit=11000.0, number_phases=3) + ], ) new_cst = to_datatype(CompositeScheduleType, cst) @@ -373,36 +449,34 @@ def test_composite_schedule_type(): assert new_cst.schedule_start == cst.schedule_start assert new_cst.charging_rate_unit == cst.charging_rate_unit assert isinstance(new_cst.charging_schedule_period[0], dict) - assert new_cst.charging_schedule_period[0]['start_period'] == cst.charging_schedule_period[0].start_period - assert new_cst.charging_schedule_period[0]['limit'] == cst.charging_schedule_period[0].limit + assert ( + new_cst.charging_schedule_period[0]["start_period"] + == cst.charging_schedule_period[0].start_period + ) + assert ( + new_cst.charging_schedule_period[0]["limit"] + == cst.charging_schedule_period[0].limit + ) def test_consumption_cost_type(): cct = ConsumptionCostType( start_value=0.0, - cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + cost=[CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0)], ) new_cct = to_datatype(ConsumptionCostType, cct) assert new_cct.start_value == cct.start_value assert isinstance(new_cct.cost[0], dict) - assert new_cct.cost[0]['cost_kind'] == cct.cost[0].cost_kind - assert new_cct.cost[0]['amount'] == cct.cost[0].amount - assert new_cct.cost[0]['amount_multiplier'] == cct.cost[0].amount_multiplier + assert new_cct.cost[0]["cost_kind"] == cct.cost[0].cost_kind + assert new_cct.cost[0]["amount"] == cct.cost[0].amount + assert new_cct.cost[0]["amount_multiplier"] == cct.cost[0].amount_multiplier def test_cost_type(): ct = CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 + cost_kind=CostKindType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 ) new_ct = to_datatype(CostType, ct) @@ -416,22 +490,16 @@ def test_event_data_type(): edt = EventDataType( event_id=1, timestamp="2024-01-01T10:00:00Z", - trigger="Alerting", + trigger=EventTriggerType.alerting, actual_value="High Temperature", tech_code="TC001", tech_info="Temperature sensor reading high", cleared=False, transaction_id="TX001", variable_monitoring_id=1, - event_notification_type="HardWiredNotification", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ) + event_notification_type=EventNotificationType.hard_wired_notification, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), ) new_edt = to_datatype(EventDataType, edt) @@ -447,9 +515,9 @@ def test_event_data_type(): assert new_edt.variable_monitoring_id == edt.variable_monitoring_id assert new_edt.event_notification_type == edt.event_notification_type assert isinstance(new_edt.component, dict) - assert new_edt.component['name'] == edt.component.name + assert new_edt.component["name"] == edt.component.name assert isinstance(new_edt.variable, dict) - assert new_edt.variable['name'] == edt.variable.name + assert new_edt.variable["name"] == edt.variable.name def test_firmware_type(): @@ -458,7 +526,7 @@ def test_firmware_type(): retrieve_date_time="2024-01-01T10:00:00Z", install_date_time="2024-01-01T11:00:00Z", signing_certificate="MIIB...", - signature="SHA256..." + signature="SHA256...", ) new_ft = to_datatype(FirmwareType, ft) @@ -472,25 +540,19 @@ def test_firmware_type(): def test_get_variable_data_type(): gvdt = GetVariableDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ), - attribute_type=AttributeType.actual + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_type=AttributeType.actual, ) new_gvdt = to_datatype(GetVariableDataType, gvdt) assert isinstance(new_gvdt.component, dict) - assert new_gvdt.component['name'] == gvdt.component.name - assert new_gvdt.component['instance'] == gvdt.component.instance + assert new_gvdt.component["name"] == gvdt.component.name + assert new_gvdt.component["instance"] == gvdt.component.instance assert isinstance(new_gvdt.variable, dict) - assert new_gvdt.variable['name'] == gvdt.variable.name - assert new_gvdt.variable['instance'] == gvdt.variable.instance + assert new_gvdt.variable["name"] == gvdt.variable.name + assert new_gvdt.variable["instance"] == gvdt.variable.instance assert new_gvdt.attribute_type == gvdt.attribute_type @@ -499,14 +561,8 @@ def test_get_variable_result_type(): attribute_status="Accepted", attribute_type=AttributeType.actual, attribute_value="100", - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="CurrentLimit", - instance="instance1" - ) + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), ) new_gvrt = to_datatype(GetVariableResultType, gvrt) @@ -515,9 +571,9 @@ def test_get_variable_result_type(): assert new_gvrt.attribute_type == gvrt.attribute_type assert new_gvrt.attribute_value == gvrt.attribute_value assert isinstance(new_gvrt.component, dict) - assert new_gvrt.component['name'] == gvrt.component.name + assert new_gvrt.component["name"] == gvrt.component.name assert isinstance(new_gvrt.variable, dict) - assert new_gvrt.variable['name'] == gvrt.variable.name + assert new_gvrt.variable["name"] == gvrt.variable.name def test_id_token_info_type(): @@ -527,12 +583,10 @@ def test_id_token_info_type(): charging_priority=1, language_1="en", language_2="fr", - group_id_token=IdTokenType.central, + group_id_token=IdTokenEnumType.central, personal_message=MessageContentType( - format=MessageFormatType.ascii, - content="Welcome back!", - language="en" - ) + format=MessageFormatType.ascii, content="Welcome back!", language="en" + ), ) new_itit = to_datatype(IdTokenInfoType, itit) @@ -545,14 +599,14 @@ def test_id_token_info_type(): assert isinstance(new_itit.group_id_token, str) assert new_itit.group_id_token == itit.group_id_token assert isinstance(new_itit.personal_message, dict) - assert new_itit.personal_message['content'] == itit.personal_message.content + assert new_itit.personal_message["content"] == itit.personal_message.content def test_log_parameters_type(): lpt = LogParametersType( remote_location="https://logs.example.com", oldest_timestamp="2024-01-01T00:00:00Z", - latest_timestamp="2024-01-01T23:59:59Z" + latest_timestamp="2024-01-01T23:59:59Z", ) new_lpt = to_datatype(LogParametersType, lpt) @@ -567,15 +621,10 @@ def test_message_info_type(): id=1, priority=1, message=MessageContentType( - format=MessageFormatType.ascii, - content="Important notice", - language="en" - ), - display=ComponentType( - name="MainDisplay", - instance="instance1" + format=MessageFormatType.ascii, content="Important notice", language="en" ), - state="Charging" + display=ComponentType(name="MainDisplay", instance="instance1"), + state=ChargingStateType.charging, ) new_mit = to_datatype(MessageInfoType, mit) @@ -583,9 +632,9 @@ def test_message_info_type(): assert new_mit.id == mit.id assert new_mit.priority == mit.priority assert isinstance(new_mit.message, dict) - assert new_mit.message['content'] == mit.message.content + assert new_mit.message["content"] == mit.message.content assert isinstance(new_mit.display, dict) - assert new_mit.display['name'] == mit.display.name + assert new_mit.display["name"] == mit.display.name assert new_mit.state == mit.state @@ -598,27 +647,24 @@ def test_meter_value_type(): context=ReadingContextType.sample_periodic, measurand=MeasurandType.voltage, phase=PhaseType.l1, - location=LocationType.outlet + location=LocationType.outlet, ) - ] + ], ) new_mvt = to_datatype(MeterValueType, mvt) assert new_mvt.timestamp == mvt.timestamp assert isinstance(new_mvt.sampled_value[0], dict) - assert new_mvt.sampled_value[0]['value'] == mvt.sampled_value[0].value - assert new_mvt.sampled_value[0]['context'] == mvt.sampled_value[0].context - assert new_mvt.sampled_value[0]['measurand'] == mvt.sampled_value[0].measurand - assert new_mvt.sampled_value[0]['phase'] == mvt.sampled_value[0].phase - assert new_mvt.sampled_value[0]['location'] == mvt.sampled_value[0].location + assert new_mvt.sampled_value[0]["value"] == mvt.sampled_value[0].value + assert new_mvt.sampled_value[0]["context"] == mvt.sampled_value[0].context + assert new_mvt.sampled_value[0]["measurand"] == mvt.sampled_value[0].measurand + assert new_mvt.sampled_value[0]["phase"] == mvt.sampled_value[0].phase + assert new_mvt.sampled_value[0]["location"] == mvt.sampled_value[0].location def test_modem_type(): - mt = ModemType( - iccid="89012345678901234567", - imsi="123456789012345" - ) + mt = ModemType(iccid="89012345678901234567", imsi="123456789012345") new_mt = to_datatype(ModemType, mt) @@ -628,32 +674,26 @@ def test_modem_type(): def test_monitoring_data_type(): mdt = MonitoringDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_monitoring=VariableMonitoringType( id=1, transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 - ) + severity=1, + ), ) new_mdt = to_datatype(MonitoringDataType, mdt) assert isinstance(new_mdt.component, dict) - assert new_mdt.component['name'] == mdt.component.name + assert new_mdt.component["name"] == mdt.component.name assert isinstance(new_mdt.variable, dict) - assert new_mdt.variable['name'] == mdt.variable.name + assert new_mdt.variable["name"] == mdt.variable.name assert isinstance(new_mdt.variable_monitoring, dict) - assert new_mdt.variable_monitoring['id'] == mdt.variable_monitoring.id - assert new_mdt.variable_monitoring['value'] == mdt.variable_monitoring.value + assert new_mdt.variable_monitoring["id"] == mdt.variable_monitoring.id + assert new_mdt.variable_monitoring["value"] == mdt.variable_monitoring.value def test_network_connection_profile_type(): @@ -663,7 +703,8 @@ def test_network_connection_profile_type(): ocpp_csms_url="wss://example.com/ocpp", message_timeout=30, security_profile=1, - ocpp_interface=OCPPInterfaceType.wired0 + ocpp_interface=OCPPInterfaceType.wired0, + vpn=VPNType.ikev2, ) new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) @@ -674,6 +715,7 @@ def test_network_connection_profile_type(): assert new_ncpt.message_timeout == ncpt.message_timeout assert new_ncpt.security_profile == ncpt.security_profile assert new_ncpt.ocpp_interface == ncpt.ocpp_interface + assert new_ncpt.vpn == ncpt.vpn def test_ocsp_request_data_type(): @@ -682,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com" + responder_url="http://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) @@ -695,10 +737,7 @@ def test_ocsp_request_data_type(): def test_relative_time_interval_type(): - rtit = RelativeTimeIntervalType( - start=0, - duration=3600 - ) + rtit = RelativeTimeIntervalType(start=0, duration=3600) new_rtit = to_datatype(RelativeTimeIntervalType, rtit) @@ -708,81 +747,89 @@ def test_relative_time_interval_type(): def test_report_data_type(): rdt = ReportDataType( - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), variable_attribute=[ VariableAttributeType( type=AttributeType.actual, value="25.5", mutability="ReadWrite", persistent=True, - constant=False + constant=False, ) ], variable_characteristics=VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True - ) + supports_monitoring=True, + ), ) new_rdt = to_datatype(ReportDataType, rdt) assert isinstance(new_rdt.component, dict) - assert new_rdt.component['name'] == rdt.component.name + assert new_rdt.component["name"] == rdt.component.name assert isinstance(new_rdt.variable, dict) - assert new_rdt.variable['name'] == rdt.variable.name + assert new_rdt.variable["name"] == rdt.variable.name assert isinstance(new_rdt.variable_attribute[0], dict) - assert new_rdt.variable_attribute[0]['type'] == rdt.variable_attribute[0].type - assert new_rdt.variable_attribute[0]['value'] == rdt.variable_attribute[0].value + assert new_rdt.variable_attribute[0]["type"] == rdt.variable_attribute[0].type + assert new_rdt.variable_attribute[0]["value"] == rdt.variable_attribute[0].value assert isinstance(new_rdt.variable_characteristics, dict) - assert new_rdt.variable_characteristics['unit'] == rdt.variable_characteristics.unit - assert new_rdt.variable_characteristics['data_type'] == rdt.variable_characteristics.data_type - assert new_rdt.variable_characteristics['supports_monitoring'] == rdt.variable_characteristics.supports_monitoring + assert new_rdt.variable_characteristics["unit"] == rdt.variable_characteristics.unit + assert ( + new_rdt.variable_characteristics["data_type"] + == rdt.variable_characteristics.data_type + ) + assert ( + new_rdt.variable_characteristics["supports_monitoring"] + == rdt.variable_characteristics.supports_monitoring + ) def test_sales_tariff_entry_type(): stet = SalesTariffEntryType( e_price_level=1, - relative_time_interval=RelativeTimeIntervalType( - start=0, - duration=3600 - ), + relative_time_interval=RelativeTimeIntervalType(start=0, duration=3600), consumption_cost=[ ConsumptionCostType( start_value=0.0, cost=[ - CostType( - cost_kind="RelativePrice", - amount=1.0, - amount_multiplier=0 - ) - ] + CostType(cost_kind="RelativePrice", amount=1.0, amount_multiplier=0) + ], ) - ] + ], ) new_stet = to_datatype(SalesTariffEntryType, stet) assert new_stet.e_price_level == stet.e_price_level assert isinstance(new_stet.relative_time_interval, dict) - assert new_stet.relative_time_interval['start'] == stet.relative_time_interval.start - assert new_stet.relative_time_interval['duration'] == stet.relative_time_interval.duration + assert new_stet.relative_time_interval["start"] == stet.relative_time_interval.start + assert ( + new_stet.relative_time_interval["duration"] + == stet.relative_time_interval.duration + ) assert isinstance(new_stet.consumption_cost[0], dict) - assert new_stet.consumption_cost[0]['start_value'] == stet.consumption_cost[0].start_value - assert isinstance(new_stet.consumption_cost[0]['cost'][0], dict) - assert new_stet.consumption_cost[0]['cost'][0]['cost_kind'] == stet.consumption_cost[0].cost[0].cost_kind - assert new_stet.consumption_cost[0]['cost'][0]['amount'] == stet.consumption_cost[0].cost[0].amount - assert new_stet.consumption_cost[0]['cost'][0]['amount_multiplier'] == stet.consumption_cost[0].cost[0].amount_multiplier + assert ( + new_stet.consumption_cost[0]["start_value"] + == stet.consumption_cost[0].start_value + ) + assert isinstance(new_stet.consumption_cost[0]["cost"][0], dict) + assert ( + new_stet.consumption_cost[0]["cost"][0]["cost_kind"] + == stet.consumption_cost[0].cost[0].cost_kind + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount"] + == stet.consumption_cost[0].cost[0].amount + ) + assert ( + new_stet.consumption_cost[0]["cost"][0]["amount_multiplier"] + == stet.consumption_cost[0].cost[0].amount_multiplier + ) def test_sampled_value_type(): @@ -793,9 +840,8 @@ def test_sampled_value_type(): phase=PhaseType.l1, location=LocationType.outlet, unit_of_measure=UnitOfMeasureType( - unit=UnitOfMeasureUnitType.v, - multiplier=0 - ) + unit=StandardizedUnitsOfMeasureType.v, multiplier=0 + ), ) new_svt = to_datatype(SampledValueType, svt) @@ -806,8 +852,8 @@ def test_sampled_value_type(): assert new_svt.phase == svt.phase assert new_svt.location == svt.location assert isinstance(new_svt.unit_of_measure, dict) - assert new_svt.unit_of_measure['unit'] == svt.unit_of_measure.unit - assert new_svt.unit_of_measure['multiplier'] == svt.unit_of_measure.multiplier + assert new_svt.unit_of_measure["unit"] == svt.unit_of_measure.unit + assert new_svt.unit_of_measure["multiplier"] == svt.unit_of_measure.multiplier def test_set_monitoring_data_type(): @@ -815,15 +861,9 @@ def test_set_monitoring_data_type(): value=100.0, type=MonitorType.upper_threshold, severity=1, - component=ComponentType( - name="MainController", - instance="instance1" - ), - variable=VariableType( - name="Temperature", - instance="instance1" - ), - id=123456 + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + id=123456, ) new_smdt = to_datatype(SetMonitoringDataType, smdt) @@ -832,17 +872,79 @@ def test_set_monitoring_data_type(): assert new_smdt.type == smdt.type assert new_smdt.severity == smdt.severity assert isinstance(new_smdt.component, dict) - assert new_smdt.component['name'] == smdt.component.name - assert new_smdt.component['instance'] == smdt.component.instance + assert new_smdt.component["name"] == smdt.component.name + assert new_smdt.component["instance"] == smdt.component.instance assert isinstance(new_smdt.variable, dict) - assert new_smdt.variable['name'] == smdt.variable.name - assert new_smdt.variable['instance'] == smdt.variable.instance + assert new_smdt.variable["name"] == smdt.variable.name + assert new_smdt.variable["instance"] == smdt.variable.instance assert new_smdt.id == smdt.id +def test_set_monitoring_result_type(): + smrt = SetMonitoringResultType( + status=SetMonitoringStatusType.accepted, + id=123, + status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set monitoring" + ), + type=MonitorType.upper_threshold, + severity=1, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="Temperature", instance="instance1"), + ) + + new_smrt = to_datatype(SetMonitoringResultType, smrt) + + assert new_smrt.status == smrt.status + assert new_smrt.id == smrt.id + assert isinstance(new_smrt.status_info, dict) + assert new_smrt.status_info["reason_code"] == smrt.status_info.reason_code + assert new_smrt.status_info["additional_info"] == smrt.status_info.additional_info + assert new_smrt.type == smrt.type + assert new_smrt.severity == smrt.severity + assert isinstance(new_smrt.component, dict) + assert new_smrt.component["name"] == smrt.component.name + assert new_smrt.component["instance"] == smrt.component.instance + assert isinstance(new_smrt.variable, dict) + assert new_smrt.variable["name"] == smrt.variable.name + assert new_smrt.variable["instance"] == smrt.variable.instance + + +def test_set_variable_result_type(): + svrt = SetVariableResultType( + attribute_type=AttributeType.actual, + attribute_status=SetVariableStatusType.accepted, + component=ComponentType(name="MainController", instance="instance1"), + variable=VariableType(name="CurrentLimit", instance="instance1"), + attribute_status_info=StatusInfoType( + reason_code=ReasonType.other, additional_info="Successfully set variable" + ), + ) + + new_svrt = to_datatype(SetVariableResultType, svrt) + + assert new_svrt.attribute_type == svrt.attribute_type + assert new_svrt.attribute_status == svrt.attribute_status + assert isinstance(new_svrt.component, dict) + assert new_svrt.component["name"] == svrt.component.name + assert new_svrt.component["instance"] == svrt.component.instance + assert isinstance(new_svrt.variable, dict) + assert new_svrt.variable["name"] == svrt.variable.name + assert new_svrt.variable["instance"] == svrt.variable.instance + assert isinstance(new_svrt.attribute_status_info, dict) + assert ( + new_svrt.attribute_status_info["reason_code"] + == svrt.attribute_status_info.reason_code + ) + assert ( + new_svrt.attribute_status_info["additional_info"] + == svrt.attribute_status_info.additional_info + ) + + def test_unit_of_measure_type(): uomt = UnitOfMeasureType( - #unit=UnitOfMeasureType.w, + # unit=UnitOfMeasureType.w, multiplier=1 ) @@ -856,9 +958,9 @@ def test_variable_attribute_type(): vat = VariableAttributeType( type=AttributeType.actual, value="25.5", - mutability="ReadWrite", + mutability=MutabilityType.read_write, persistent=True, - constant=False + constant=False, ) new_vat = to_datatype(VariableAttributeType, vat) @@ -873,11 +975,11 @@ def test_variable_attribute_type(): def test_variable_characteristics_type(): vct = VariableCharacteristicsType( unit="Celsius", - data_type="decimal", + data_type=DataType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], - supports_monitoring=True + supports_monitoring=True, ) new_vct = to_datatype(VariableCharacteristicsType, vct) @@ -896,7 +998,7 @@ def test_variable_monitoring_type(): transaction=True, value=100.0, type=MonitorType.upper_threshold, - severity=1 + severity=1, ) new_vmt = to_datatype(VariableMonitoringType, vmt) @@ -906,9 +1008,3 @@ def test_variable_monitoring_type(): assert new_vmt.value == vmt.value assert new_vmt.type == vmt.type assert new_vmt.severity == vmt.severity - - - - - - From 75c38cdb75493f01064f1f5b61729ab81475455f Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Mon, 25 Nov 2024 22:31:39 -0500 Subject: [PATCH 17/27] even though it's a fake url, flagged as issue by sonarqube --- tests/v201/test_v201_data_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 4fe65a15e..735aa3192 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -724,7 +724,7 @@ def test_ocsp_request_data_type(): issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", - responder_url="http://ocsp.example.com", + responder_url="https://ocsp.example.com", ) new_ordt = to_datatype(OCSPRequestDataType, ordt) From c8b8f348462645fbb6e92dc3d4be7e3535ef59e0 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Tue, 26 Nov 2024 10:07:45 -0500 Subject: [PATCH 18/27] adding deprecation warnings for enums IdTokenType and UnitOfMeasureType. eliminates breaking change. --- ocpp/v201/enums.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 421553890..3a0449572 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -10,6 +10,26 @@ class StrEnum(str, Enum): # pragma: no cover pass # pragma: no cover +class DeprecatedEnumWrapper: + """ + Since enums can't be subclassed in order to add a deprecation warning, + this class is included to help warn users of deprecated enums. + """ + + def __init__(self, enum_class, alias_name): + self.enum_class = enum_class + self.alias_name = alias_name + + def __getattr__(self, name): + warn( + ( + f"Enum '{self.alias_name}' is deprecated, " + + "instead use '{self.enum_class.__name__}'" + ) + ) + return getattr(self.enum_class, name) + + class Action(StrEnum): """An Action is a required part of a Call message.""" @@ -736,6 +756,9 @@ class IdTokenEnumType(StrEnum): no_authorization = "NoAuthorization" +IdTokenType = DeprecatedEnumWrapper(IdTokenEnumType, "IdTokenType") + + class InstallCertificateStatusType(StrEnum): """ InstallCertificateStatusEnumType is used by @@ -1364,6 +1387,11 @@ class StandardizedUnitsOfMeasureType(StrEnum): k = "K" +UnitOfMeasureType = DeprecatedEnumWrapper( + StandardizedUnitsOfMeasureType, "UnitOfMeasureType" +) + + class StatusInfoReasonType(StrEnum): """ Standardized reason codes for StatusInfo defined in Appendix 5. v1.3 From b92814318c6b4e2742a77be40bbca2592ebc89ca Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Tue, 26 Nov 2024 10:17:40 -0500 Subject: [PATCH 19/27] removing files associated with a different pull request --- .github/pull_request_template.md | 21 --------- CODE_OF_CONDUCT.md | 74 -------------------------------- CONTRIBUTING.md | 41 ------------------ SECURITY.md | 33 -------------- SUPPORT.md | 34 --------------- 5 files changed, 203 deletions(-) delete mode 100644 .github/pull_request_template.md delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 SECURITY.md delete mode 100644 SUPPORT.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 2e8477f4b..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,21 +0,0 @@ -### Changes included in this PR - -*(Bug fix, feature, docs update, ...)* - -### Current behavior - -*Link to an open issue here...* - -### New behavior - -*If this is a feature change, describe the new behavior* - -### Impact - -*Describe breaking changes, including changes a users might need to make due to this PR* - -### Checklist - -1. [ ] Does your submission pass the existing tests? -2. [ ] Are there new tests that cover these additions/changes? -3. [ ] Have you linted your code locally before submission? diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 86a391351..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at {{ email }}. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index b0037efe8..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,41 +0,0 @@ -## Contributing - -[fork]: /fork -[pr]: /compare -[style]: https://standardjs.com/ -[code-of-conduct]: CODE_OF_CONDUCT.md - -Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. - -Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. - -## Issues and PRs - -If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them. - -We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR. - -Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you. - -## Submitting a pull request - -1. [Fork][fork] and clone the repository. -1. Create a new branch: `git checkout -b my-branch-name`. -1. Configure and install the dependencies: `poetry install`. -1. Make sure the tests pass on your machine: `make install & make tests` -1. Make your change, add tests, and make sure the tests still pass. -1. Push to your fork and [submit a pull request][pr] and complete the information in the pull request template. - -## Linting requirements - -using `make install & make tests` will also run the following linters: - -- [Black: The uncompromising Python code formatter](https://black.readthedocs.io/en/stable/) -- [isort your imports, so you don't have to](https://pycqa.github.io/isort/) -- [flake8: Your Tool For Style Guide Enforcement](https://flake8.pycqa.org/en/latest/) - -## Resources - -- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) -- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) -- [GitHub Help](https://help.github.com) diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index bd76a0f69..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,33 +0,0 @@ -# Security Policy - -This document outlines security procedures and general policies for this OCPP project. - -## Supported Versions - -The currently supported versions of this OCPP project are: - -| Version | Supported | -|----------| ------------------ | -| 2.0.0 | :white_check_mark: | -| 0.26.0 | :white_check_mark: | -| < 0.26.0 | :x: | - -## Reporting a Vulnerability - -Please include the requested information listed below (as much as you can provide) to help -us better understand the nature and scope of the possible issue: - -- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) -- Full paths of source file(s) related to the manifestation of the issue -- The location of the affected source code (tag/branch/commit or direct URL) -- Any special configuration required to reproduce the issue -- Step-by-step instructions to reproduce the issue -- Proof-of-concept or exploit code (if possible) -- Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -## Comments on this Policy - -If you have suggestions on how this process could be improved please submit a -pull request. Thanks! diff --git a/SUPPORT.md b/SUPPORT.md deleted file mode 100644 index 72b64a6c6..000000000 --- a/SUPPORT.md +++ /dev/null @@ -1,34 +0,0 @@ -# Support - -This article explains where to get help with this OCPP project. -Please read through the following guidelines. - -> 👉 **Note**: before participating in our community, please read our -> [code of conduct][coc]. -> By interacting with this repository, organization, or community you agree to -> abide by its terms. - -## Asking quality questions - -Questions can go to [GitHub discussions][chat]. - -Help us help you! -Spend time framing questions and add links and resources. -Spending the extra time up front can help save everyone time in the long run. -Here are some tips: - -* Search to find out if a similar question has been asked or a similar issue has been reported -* Check to see if a PR is already in progress for the issue you want to raise -* Try to define what you need help with: - * Is there something in particular you want to do? - * What problem are you encountering and what steps have you taken to try - and fix it? - * Is there a concept you don’t understand? -* Provide sample code, such as a [CodeSandbox][cs] or video, if possible -* Screenshots can help, but if there’s important text such as code or error - messages in them, please also provide those as text -* The more time you put into asking your question, the better we can help you - -## Contributions - -See [`contributing.md`][contributing] on how to contribute. From 5bbbf317b26a9bc8e8e959bc3fffc86220d211e8 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 10:38:05 -0500 Subject: [PATCH 20/27] correcting class names of Enum Types --- ocpp/v201/call.py | 56 ++++----- ocpp/v201/call_result.py | 80 ++++++------- ocpp/v201/datatypes.py | 92 +++++++-------- ocpp/v201/enums.py | 180 ++++++++++++++--------------- tests/test_charge_point.py | 10 +- tests/v201/test_v201_data_types.py | 148 ++++++++++++------------ tests/v201/test_v201_enums.py | 82 ++++++------- 7 files changed, 324 insertions(+), 324 deletions(-) diff --git a/ocpp/v201/call.py b/ocpp/v201/call.py index 0f60762b5..7ffdb46dd 100644 --- a/ocpp/v201/call.py +++ b/ocpp/v201/call.py @@ -16,7 +16,7 @@ class Authorize: @dataclass class BootNotification: charging_station: datatypes.ChargingStationType - reason: enums.BootReasonType + reason: enums.BootReasonEnumType custom_data: Optional[Dict[str, Any]] = None @@ -29,13 +29,13 @@ class CancelReservation: @dataclass class CertificateSigned: certificate_chain: str - certificate_type: Optional[enums.CertificateSigningUseType] = None + certificate_type: Optional[enums.CertificateSigningUseEnumType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - operational_status: enums.OperationalStatusType + operational_status: enums.OperationalStatusEnumType evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None @@ -66,7 +66,7 @@ class ClearVariableMonitoring: @dataclass class ClearedChargingLimit: - charging_limit_source: enums.ChargingLimitSourceType + charging_limit_source: enums.ChargingLimitSourceEnumType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -105,7 +105,7 @@ class DeleteCertificate: @dataclass class FirmwareStatusNotification: - status: enums.FirmwareStatusType + status: enums.FirmwareStatusEnumType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -113,7 +113,7 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: iso15118_schema_version: str - action: enums.CertificateActionType + action: enums.CertificateActionEnumType exi_request: str custom_data: Optional[Dict[str, Any]] = None @@ -121,7 +121,7 @@ class Get15118EVCertificate: @dataclass class GetBaseReport: request_id: int - report_base: enums.ReportBaseType + report_base: enums.ReportBaseEnumType custom_data: Optional[Dict[str, Any]] = None @@ -143,7 +143,7 @@ class GetChargingProfiles: class GetCompositeSchedule: duration: int evse_id: int - charging_rate_unit: Optional[enums.ChargingRateUnitType] = None + charging_rate_unit: Optional[enums.ChargingRateUnitEnumType] = None custom_data: Optional[Dict[str, Any]] = None @@ -151,14 +151,14 @@ class GetCompositeSchedule: class GetDisplayMessages: request_id: int id: Optional[List[int]] = None - priority: Optional[enums.MessagePriorityType] = None - state: Optional[enums.MessageStateType] = None + priority: Optional[enums.MessagePriorityEnumType] = None + state: Optional[enums.MessageStateEnumType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - certificate_type: Optional[List[enums.GetCertificateIdUseType]] = None + certificate_type: Optional[List[enums.GetCertificateIdUseEnumType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -170,7 +170,7 @@ class GetLocalListVersion: @dataclass class GetLog: log: datatypes.LogParametersType - log_type: enums.LogType + log_type: enums.LogEnumType request_id: int retries: Optional[int] = None retry_interval: Optional[int] = None @@ -181,7 +181,7 @@ class GetLog: class GetMonitoringReport: request_id: int component_variable: Optional[List[datatypes.ComponentVariableType]] = None - monitoring_criteria: Optional[List[enums.MonitoringCriterionType]] = None + monitoring_criteria: Optional[List[enums.MonitoringCriterionEnumType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -189,7 +189,7 @@ class GetMonitoringReport: class GetReport: request_id: int component_variable: Optional[List[datatypes.ComponentVariableType]] = None - component_criteria: Optional[List[enums.ComponentCriterionType]] = None + component_criteria: Optional[List[enums.ComponentCriterionEnumType]] = None custom_data: Optional[Dict[str, Any]] = None @@ -212,14 +212,14 @@ class Heartbeat: @dataclass class InstallCertificate: - certificate_type: enums.InstallCertificateUseType + certificate_type: enums.InstallCertificateUseEnumType certificate: str custom_data: Optional[Dict[str, Any]] = None @dataclass class LogStatusNotification: - status: enums.UploadLogStatusType + status: enums.UploadLogStatusEnumType request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -314,7 +314,7 @@ class PublishFirmware: @dataclass class PublishFirmwareStatusNotification: - status: enums.PublishFirmwareStatusType + status: enums.PublishFirmwareStatusEnumType location: Optional[List[str]] = None request_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -323,7 +323,7 @@ class PublishFirmwareStatusNotification: @dataclass class ReportChargingProfiles: request_id: int - charging_limit_source: enums.ChargingLimitSourceType + charging_limit_source: enums.ChargingLimitSourceEnumType charging_profile: List[datatypes.ChargingProfileType] evse_id: int tbc: Optional[bool] = None @@ -349,7 +349,7 @@ class RequestStopTransaction: @dataclass class ReservationStatusUpdate: reservation_id: int - reservation_update_status: enums.ReservationUpdateStatusType + reservation_update_status: enums.ReservationUpdateStatusEnumType custom_data: Optional[Dict[str, Any]] = None @@ -358,7 +358,7 @@ class ReserveNow: id: int expiry_date_time: str id_token: datatypes.IdTokenType - connector_type: Optional[enums.ConnectorType] = None + connector_type: Optional[enums.ConnectorEnumType] = None evse_id: Optional[int] = None group_id_token: Optional[datatypes.IdTokenType] = None custom_data: Optional[Dict[str, Any]] = None @@ -366,7 +366,7 @@ class ReserveNow: @dataclass class Reset: - type: enums.ResetType + type: enums.ResetEnumType evse_id: Optional[int] = None custom_data: Optional[Dict[str, Any]] = None @@ -382,7 +382,7 @@ class SecurityEventNotification: @dataclass class SendLocalList: version_number: int - update_type: enums.UpdateType + update_type: enums.UpdateEnumType local_authorization_list: Optional[List[datatypes.AuthorizationData]] = None custom_data: Optional[Dict[str, Any]] = None @@ -402,7 +402,7 @@ class SetDisplayMessage: @dataclass class SetMonitoringBase: - monitoring_base: enums.MonitorBaseType + monitoring_base: enums.MonitorBaseEnumType custom_data: Optional[Dict[str, Any]] = None @@ -434,14 +434,14 @@ class SetVariables: @dataclass class SignCertificate: csr: str - certificate_type: Optional[enums.CertificateSigningUseType] = None + certificate_type: Optional[enums.CertificateSigningUseEnumType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class StatusNotification: timestamp: str - connector_status: enums.ConnectorStatusType + connector_status: enums.ConnectorStatusEnumType evse_id: int connector_id: int custom_data: Optional[Dict[str, Any]] = None @@ -449,9 +449,9 @@ class StatusNotification: @dataclass class TransactionEvent: - event_type: enums.TransactionEventType + event_type: enums.TransactionEventEnumType timestamp: str - trigger_reason: enums.TriggerReasonType + trigger_reason: enums.TriggerReasonEnumType seq_no: int transaction_info: datatypes.TransactionType meter_value: Optional[List[datatypes.MeterValueType]] = None @@ -466,7 +466,7 @@ class TransactionEvent: @dataclass class TriggerMessage: - requested_message: enums.MessageTriggerType + requested_message: enums.MessageTriggerEnumType evse: Optional[datatypes.EVSEType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index 006001715..f603b1cba 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -8,7 +8,7 @@ @dataclass class Authorize: id_token_info: datatypes.IdTokenInfoType - certificate_status: Optional[enums.AuthorizeCertificateStatusType] = None + certificate_status: Optional[enums.AuthorizeCertificateStatusEnumType] = None custom_data: Optional[Dict[str, Any]] = None @@ -16,56 +16,56 @@ class Authorize: class BootNotification: current_time: str interval: int - status: enums.RegistrationStatusType + status: enums.RegistrationStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CancelReservation: - status: enums.CancelReservationStatusType + status: enums.CancelReservationStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class CertificateSigned: - status: enums.CertificateSignedStatusType + status: enums.CertificateSignedStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ChangeAvailability: - status: enums.ChangeAvailabilityStatusType + status: enums.ChangeAvailabilityStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearCache: - status: enums.ClearCacheStatusType + status: enums.ClearCacheStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearChargingProfile: - status: enums.ClearChargingProfileStatusType + status: enums.ClearChargingProfileStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearDisplayMessage: - status: enums.ClearMessageStatusType + status: enums.ClearMessageStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class ClearVariableMonitoring: - clear_monitoring_result: List[enums.ClearMonitoringStatusType] + clear_monitoring_result: List[enums.ClearMonitoringStatusEnumType] custom_data: Optional[Dict[str, Any]] = None @@ -81,14 +81,14 @@ class CostUpdated: @dataclass class CustomerInformation: - status: enums.CustomerInformationStatusType + status: enums.CustomerInformationStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class DataTransfer: - status: enums.DataTransferStatusType + status: enums.DataTransferStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None data: Optional[Any] = None custom_data: Optional[Dict[str, Any]] = None @@ -96,7 +96,7 @@ class DataTransfer: @dataclass class DeleteCertificate: - status: enums.DeleteCertificateStatusType + status: enums.DeleteCertificateStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -108,7 +108,7 @@ class FirmwareStatusNotification: @dataclass class Get15118EVCertificate: - status: enums.Iso15118EVCertificateStatusType + status: enums.Iso15118EVCertificateStatusEnumType exi_response: str status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -116,14 +116,14 @@ class Get15118EVCertificate: @dataclass class GetBaseReport: - status: enums.GenericDeviceModelStatusType + status: enums.GenericDeviceModelStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCertificateStatus: - status: enums.GetCertificateStatusType + status: enums.GetCertificateStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None ocsp_result: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @@ -131,14 +131,14 @@ class GetCertificateStatus: @dataclass class GetChargingProfiles: - status: enums.GetChargingProfileStatusType + status: enums.GetChargingProfileStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetCompositeSchedule: - status: enums.GenericStatusType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None schedule: Optional[datatypes.CompositeScheduleType] = None custom_data: Optional[Dict[str, Any]] = None @@ -146,14 +146,14 @@ class GetCompositeSchedule: @dataclass class GetDisplayMessages: - status: enums.GetDisplayMessagesStatusType + status: enums.GetDisplayMessagesStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetInstalledCertificateIds: - status: enums.GetInstalledCertificateStatusType + status: enums.GetInstalledCertificateStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None certificate_hash_data_chain: Optional[ List[datatypes.CertificateHashDataChainType] @@ -169,7 +169,7 @@ class GetLocalListVersion: @dataclass class GetLog: - status: enums.LogStatusType + status: enums.LogStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None filename: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @@ -177,14 +177,14 @@ class GetLog: @dataclass class GetMonitoringReport: - status: enums.GenericDeviceModelStatusType + status: enums.GenericDeviceModelStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class GetReport: - status: enums.GenericDeviceModelStatusType + status: enums.GenericDeviceModelStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -210,7 +210,7 @@ class Heartbeat: @dataclass class InstallCertificate: - status: enums.InstallCertificateStatusType + status: enums.InstallCertificateStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -242,14 +242,14 @@ class NotifyDisplayMessages: @dataclass class NotifyEVChargingNeeds: - status: enums.NotifyEVChargingNeedsStatusType + status: enums.NotifyEVChargingNeedsStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class NotifyEVChargingSchedule: - status: enums.GenericStatusType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -271,7 +271,7 @@ class NotifyReport: @dataclass class PublishFirmware: - status: enums.PublishFirmwareStatusType + status: enums.PublishFirmwareStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -288,7 +288,7 @@ class ReportChargingProfiles: @dataclass class RequestStartTransaction: - status: enums.RequestStartStopStatusType + status: enums.RequestStartStopStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None transaction_id: Optional[str] = None custom_data: Optional[Dict[str, Any]] = None @@ -296,7 +296,7 @@ class RequestStartTransaction: @dataclass class RequestStopTransaction: - status: enums.RequestStartStopStatusType + status: enums.RequestStartStopStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -308,14 +308,14 @@ class ReservationStatusUpdate: @dataclass class ReserveNow: - status: enums.ReserveNowStatusType + status: enums.ReserveNowStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class Reset: - status: enums.ResetStatusType + status: enums.ResetStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -327,7 +327,7 @@ class SecurityEventNotification: @dataclass class SendLocalList: - status: enums.SendLocalListStatusType + status: enums.SendLocalListStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -341,28 +341,28 @@ class SetChargingProfile: @dataclass class SetDisplayMessage: - status: enums.DisplayMessageStatusType + status: enums.DisplayMessageStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringBase: - status: enums.GenericStatusType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetMonitoringLevel: - status: enums.GenericStatusType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class SetNetworkProfile: - status: enums.SetNetworkProfileStatusType + status: enums.SetNetworkProfileStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -381,7 +381,7 @@ class SetVariables: @dataclass class SignCertificate: - status: enums.GenericStatusType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -402,27 +402,27 @@ class TransactionEvent: @dataclass class TriggerMessage: - status: enums.TriggerMessageStatusType + status: enums.TriggerMessageStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnlockConnector: - status: enums.UnlockStatusType + status: enums.UnlockStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @dataclass class UnpublishFirmware: - status: enums.UnpublishFirmwareStatusType + status: enums.UnpublishFirmwareStatusEnumType custom_data: Optional[Dict[str, Any]] = None @dataclass class UpdateFirmware: - status: enums.FirmwareStatusType + status: enums.FirmwareStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 59c80b24c..68255f702 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -38,7 +38,7 @@ class APNType: """ apn: str - apn_authentication: enums.APNAuthenticationType + apn_authentication: enums.APNAuthenticationEnumType apn_user_name: Optional[str] = None apn_password: Optional[str] = None sim_pin: Optional[int] = None @@ -53,7 +53,7 @@ class CertificateHashDataType: DeleteCertificateRequest, CustomerInformationRequest """ - hash_algorithm: enums.HashAlgorithmType + hash_algorithm: enums.HashAlgorithmEnumType issuer_name_hash: str issuer_key_hash: str serial_number: str @@ -65,7 +65,7 @@ class CertificateHashDataChainType: CertificateHashDataChainType is used by: GetInstalledCertificateIdsResponse """ - certificate_type: enums.GetCertificateIdUseType + certificate_type: enums.GetCertificateIdUseEnumType certificate_hash_data: CertificateHashDataType child_certificate_hash_data: Optional[List[CertificateHashDataType]] = None @@ -74,7 +74,7 @@ class CertificateHashDataChainType: class ChargingLimitType: """ChargingLimitType is used by: NotifyChargingLimitRequest""" - charging_limit_source: enums.ChargingLimitSourceType + charging_limit_source: enums.ChargingLimitSourceEnumType is_grid_critical: Optional[bool] = None @@ -101,7 +101,7 @@ class ChargingNeedsType: ChargingNeedsType is used by: NotifyEVChargingNeedsRequest """ - requested_energy_transfer: enums.EnergyTransferModeType + requested_energy_transfer: enums.EnergyTransferModeEnumType departure_time: Optional[str] = None ac_charging_parameters: Optional[ACChargingParametersType] = None dc_charging_parameters: Optional[DCChargingParametersType] = None @@ -115,10 +115,10 @@ class ChargingProfileCriterionType: ChargingProfileCriterionType is used by: GetChargingProfilesRequest """ - charging_profile_purpose: Optional[enums.ChargingProfilePurposeType] = None + charging_profile_purpose: Optional[enums.ChargingProfilePurposeEnumType] = None stack_level: Optional[int] = None charging_profile_id: Optional[List[int]] = None - charging_limit_source: Optional[List[enums.ChargingLimitSourceType]] = None + charging_limit_source: Optional[List[enums.ChargingLimitSourceEnumType]] = None @dataclass @@ -150,7 +150,7 @@ class CostType: CostType is used by: ConsumptionCostType """ - cost_kind: enums.CostKindType + cost_kind: enums.CostKindEnumType amount: int amount_multiplier: Optional[int] = None @@ -197,7 +197,7 @@ class ChargingScheduleType: """ id: int - charging_rate_unit: enums.ChargingRateUnitType + charging_rate_unit: enums.ChargingRateUnitEnumType charging_schedule_period: List[ChargingSchedulePeriodType] start_schedule: Optional[str] = None duration: Optional[int] = None @@ -216,13 +216,13 @@ class ChargingProfileType: id: int stack_level: int - charging_profile_purpose: enums.ChargingProfilePurposeType - charging_profile_kind: enums.ChargingProfileKindType + charging_profile_purpose: enums.ChargingProfilePurposeEnumType + charging_profile_kind: enums.ChargingProfileKindEnumType charging_schedule: List[ChargingScheduleType] valid_from: Optional[str] = None valid_to: Optional[str] = None transaction_id: Optional[str] = None - recurrency_kind: Optional[enums.RecurrencyKindType] = None + recurrency_kind: Optional[enums.RecurrencyKindEnumType] = None @dataclass @@ -234,7 +234,7 @@ class ClearChargingProfileType: """ evse_id: Optional[int] = None - charging_profile_purpose: Optional[enums.ChargingProfilePurposeType] = None + charging_profile_purpose: Optional[enums.ChargingProfilePurposeEnumType] = None stack_level: Optional[int] = None @@ -274,7 +274,7 @@ class ClearMonitoringResultType: ClearMonitoringResultType is used by: ClearVariableMonitoringResponse """ - status: enums.ClearMonitoringStatusType + status: enums.ClearMonitoringStatusEnumType id: int status_info: Optional[StatusInfoType] = None @@ -354,7 +354,7 @@ class CompositeScheduleType: evse_id: int duration: int schedule_start: str - charging_rate_unit: enums.ChargingRateUnitType + charging_rate_unit: enums.ChargingRateUnitEnumType charging_schedule_period: List[ChargingSchedulePeriodType] @@ -364,7 +364,7 @@ class CostType: CostType is used by: ConsumptionCostType """ - cost_kind: enums.CostKindType + cost_kind: enums.CostKindEnumType amount: int amount_multiplier: Optional[int] = None @@ -388,9 +388,9 @@ class EventDataType: event_id: int timestamp: str - trigger: enums.EventTriggerType + trigger: enums.EventTriggerEnumType actual_value: str - event_notification_type: enums.EventNotificationType + event_notification_type: enums.EventNotificationEnumType component: ComponentType variable: VariableType cause: Optional[int] = None @@ -425,7 +425,7 @@ class GetVariableDataType: component: ComponentType variable: VariableType - attribute_type: Optional[enums.AttributeType] = None + attribute_type: Optional[enums.AttributeEnumType] = None @dataclass @@ -435,10 +435,10 @@ class GetVariableResultType: GetVariableResultType is used by: GetVariablesResponse """ - attribute_status: enums.GetVariableStatusType + attribute_status: enums.GetVariableStatusEnumType component: ComponentType variable: VariableType - attribute_type: Optional[enums.AttributeType] = None + attribute_type: Optional[enums.AttributeEnumType] = None attribute_value: Optional[str] = None attribute_status_info: Optional[StatusInfoType] = None @@ -467,7 +467,7 @@ class MessageContentType: TransactionEventResponse """ - format: enums.MessageFormatType + format: enums.MessageFormatEnumType content: str language: Optional[str] = None @@ -483,7 +483,7 @@ class IdTokenInfoType: TransactionEventResponse """ - status: enums.AuthorizationStatusType + status: enums.AuthorizationStatusEnumType cache_expiry_date_time: Optional[str] = None charging_priority: Optional[int] = None language_1: Optional[str] = None @@ -526,9 +526,9 @@ class MessageInfoType: """ id: int - priority: enums.MessagePriorityType + priority: enums.MessagePriorityEnumType message: MessageContentType - state: Optional[enums.MessageStateType] = None + state: Optional[enums.MessageStateEnumType] = None start_date_time: Optional[str] = None end_date_time: Optional[str] = None transaction_id: Optional[str] = None @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.StandardizedUnitsOfMeasureType] = None + unit: Optional[enums.StandardizedUnitsOfMeasureEnumType] = None multiplier: Optional[int] = None @@ -571,10 +571,10 @@ class SampledValueType: """ value: float - context: Optional[enums.ReadingContextType] = None - measurand: Optional[enums.MeasurandType] = None - phase: Optional[enums.PhaseType] = None - location: Optional[enums.LocationType] = None + context: Optional[enums.ReadingContextEnumType] = None + measurand: Optional[enums.MeasurandEnumType] = None + phase: Optional[enums.PhaseEnumType] = None + location: Optional[enums.LocationEnumType] = None signed_meter_value: Optional[SignedMeterValueType] = None unit_of_measure: Optional[UnitOfMeasureType] = None @@ -615,7 +615,7 @@ class VariableMonitoringType: id: int transaction: bool value: float - type: enums.MonitorType + type: enums.MonitorEnumType severity: int @@ -654,12 +654,12 @@ class NetworkConnectionProfileType: NetworkConnectionProfileType is used by: SetNetworkProfileRequest """ - ocpp_version: enums.OCPPVersionType - ocpp_transport: enums.OCPPTransportType + ocpp_version: enums.OCPPVersionEnumType + ocpp_transport: enums.OCPPTransportEnumType ocpp_csms_url: str message_timeout: int security_profile: int - ocpp_interface: enums.OCPPInterfaceType + ocpp_interface: enums.OCPPInterfaceEnumType vpn: Optional[VPNType] = None apn: Optional[APNType] = None @@ -685,7 +685,7 @@ class OCSPRequestDataType: GetCertificateStatusRequest """ - hash_algorithm: enums.HashAlgorithmType + hash_algorithm: enums.HashAlgorithmEnumType issuer_name_hash: str issuer_key_hash: str serial_number: str @@ -699,9 +699,9 @@ class VariableAttributeType: VariableAttributeType is used by: NotifyReportRequest.ReportDataType """ - type: Optional[enums.AttributeType] = None + type: Optional[enums.AttributeEnumType] = None value: Optional[str] = None - mutability: Optional[enums.MutabilityType] = None + mutability: Optional[enums.MutabilityEnumType] = None persistent: Optional[bool] = None constant: Optional[bool] = None @@ -713,7 +713,7 @@ class VariableCharacteristicsType: VariableCharacteristicsType is used by: NotifyReportRequest.ReportDataType """ - data_type: enums.DataType + data_type: enums.DataEnumEnumType supports_monitoring: bool unit: Optional[str] = None min_limit: Optional[float] = None @@ -756,7 +756,7 @@ class SetMonitoringDataType: """ value: float - type: enums.MonitorType + type: enums.MonitorEnumType severity: int component: ComponentType variable: VariableType @@ -771,8 +771,8 @@ class SetMonitoringResultType: SetMonitoringResultType is used by: SetVariableMonitoringResponse """ - status: enums.SetMonitoringStatusType - type: enums.MonitorType + status: enums.SetMonitoringStatusEnumType + type: enums.MonitorEnumType severity: int component: ComponentType variable: VariableType @@ -787,17 +787,17 @@ class SetVariableDataType: attribute_value: str component: ComponentType variable: VariableType - attribute_type: Optional[enums.AttributeType] = None + attribute_type: Optional[enums.AttributeEnumType] = None @dataclass class SetVariableResultType: """SetVariableResultType is used by: SetVariablesResponse""" - attribute_status: enums.SetVariableStatusType + attribute_status: enums.SetVariableStatusEnumType component: ComponentType variable: VariableType - attribute_type: Optional[enums.AttributeType] = None + attribute_type: Optional[enums.AttributeEnumType] = None attribute_status_info: Optional[StatusInfoType] = None @@ -806,7 +806,7 @@ class TransactionType: """TransactionType is used by: TransactionEventRequest""" transaction_id: str - charging_state: Optional[enums.ChargingStateType] = None + charging_state: Optional[enums.ChargingStateEnumType] = None time_spent_charging: Optional[int] = None - stopped_reason: Optional[enums.ReasonType] = None + stopped_reason: Optional[enums.ReasonEnumType] = None remote_start_id: Optional[int] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 3a0449572..01c3f6a84 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -173,7 +173,7 @@ def __init__(self, *args, **kwargs): update_firmware = "UpdateFirmware" -class APNAuthenticationType(StrEnum): +class APNAuthenticationEnumType(StrEnum): """ APNAuthenticationEnumType is used by setNetworkProfileSetNetworkProfileRequest.APNType @@ -185,7 +185,7 @@ class APNAuthenticationType(StrEnum): auto = "AUTO" -class AttributeType(StrEnum): +class AttributeEnumType(StrEnum): """ AttributeEnumType is used by Common:VariableAttributeType, getVariables:GetVariablesRequest.GetVariableDataType , @@ -201,7 +201,7 @@ class AttributeType(StrEnum): max_set = "MaxSet" -class AuthorizationStatusType(StrEnum): +class AuthorizationStatusEnumType(StrEnum): """ Elements that constitute an entry of a Local Authorization List update. """ @@ -221,7 +221,7 @@ class AuthorizationStatusType(StrEnum): unknown = "Unknown" -class AuthorizeCertificateStatusType(StrEnum): +class AuthorizeCertificateStatusEnumType(StrEnum): """ Status of the EV Contract certificate. """ @@ -235,7 +235,7 @@ class AuthorizeCertificateStatusType(StrEnum): contract_cancelled = "ContractCancelled" -class BootReasonType(StrEnum): +class BootReasonEnumType(StrEnum): """ BootReasonEnumType is used by bootNotificationBootNotificationRequest """ @@ -251,7 +251,7 @@ class BootReasonType(StrEnum): watchdog = "Watchdog" -class CancelReservationStatusType(StrEnum): +class CancelReservationStatusEnumType(StrEnum): """ Status in CancelReservationResponse. """ @@ -260,7 +260,7 @@ class CancelReservationStatusType(StrEnum): rejected = "Rejected" -class CertificateActionType(StrEnum): +class CertificateActionEnumType(StrEnum): """ CertificateActionEnumType is used by get15118EVCertificateGet15118EVCertificateRequest @@ -270,12 +270,12 @@ class CertificateActionType(StrEnum): update = "Update" -class CertificateSignedStatusType(StrEnum): +class CertificateSignedStatusEnumType(StrEnum): accepted = "Accepted" rejected = "Rejected" -class CertificateSigningUseType(StrEnum): +class CertificateSigningUseEnumType(StrEnum): """ CertificateSigningUseEnumType is used by signCertificate SignCertificateRequest , @@ -286,7 +286,7 @@ class CertificateSigningUseType(StrEnum): v2g_certificate = "V2GCertificate" -class ChangeAvailabilityStatusType(StrEnum): +class ChangeAvailabilityStatusEnumType(StrEnum): """ Status returned in response to ChangeAvailability.req. """ @@ -296,7 +296,7 @@ class ChangeAvailabilityStatusType(StrEnum): scheduled = "Scheduled" -class ChargingLimitSourceType(StrEnum): +class ChargingLimitSourceEnumType(StrEnum): """ Enumeration for indicating from which source a charging limit originates. """ @@ -307,7 +307,7 @@ class ChargingLimitSourceType(StrEnum): cso = "CSO" -class ChargingProfileKindType(StrEnum): +class ChargingProfileKindEnumType(StrEnum): """ "Absolute" Schedule periods are relative to a fixed point in time defined in the schedule. @@ -321,7 +321,7 @@ class ChargingProfileKindType(StrEnum): relative = "Relative" -class ChargingProfilePurposeType(StrEnum): +class ChargingProfilePurposeEnumType(StrEnum): """ In load balancing scenarios, the Charge Point has one or more local charging profiles that limit the power or current to be shared by all @@ -374,7 +374,7 @@ class ChargingProfileStatus(StrEnum): rejected = "Rejected" -class ChargingRateUnitType(StrEnum): +class ChargingRateUnitEnumType(StrEnum): """ Unit in which a charging schedule is defined, as used in GetCompositeSchedule.req and ChargingSchedule @@ -384,7 +384,7 @@ class ChargingRateUnitType(StrEnum): amps = "A" -class ChargingStateType(StrEnum): +class ChargingStateEnumType(StrEnum): """ The state of the charging process. """ @@ -396,7 +396,7 @@ class ChargingStateType(StrEnum): idle = "Idle" -class ClearCacheStatusType(StrEnum): +class ClearCacheStatusEnumType(StrEnum): """ Status returned in response to ClearCache.req. """ @@ -405,7 +405,7 @@ class ClearCacheStatusType(StrEnum): rejected = "Rejected" -class ClearChargingProfileStatusType(StrEnum): +class ClearChargingProfileStatusEnumType(StrEnum): """ Status returned in response to ClearChargingProfile.req. """ @@ -414,7 +414,7 @@ class ClearChargingProfileStatusType(StrEnum): unknown = "Unknown" -class ClearMessageStatusType(StrEnum): +class ClearMessageStatusEnumType(StrEnum): """ Status returned in response to ClearDisplayMessageRequest. """ @@ -423,7 +423,7 @@ class ClearMessageStatusType(StrEnum): unknown = "Unknown" -class ClearMonitoringStatusType(StrEnum): +class ClearMonitoringStatusEnumType(StrEnum): """ ClearMonitoringStatusEnumType is used by CommonClearMonitoringResultType """ @@ -433,7 +433,7 @@ class ClearMonitoringStatusType(StrEnum): not_found = "NotFound" -class ComponentCriterionType(StrEnum): +class ComponentCriterionEnumType(StrEnum): """ ComponentCriterionEnumType is used by getReportGetReportRequest """ @@ -444,7 +444,7 @@ class ComponentCriterionType(StrEnum): problem = "Problem" -class ConnectorStatusType(StrEnum): +class ConnectorStatusEnumType(StrEnum): """ Status reported in StatusNotification.req. A status can be reported for the Charge Point main controller (connectorId = 0) or for a specific @@ -463,7 +463,7 @@ class ConnectorStatusType(StrEnum): faulted = "Faulted" -class ConnectorType(StrEnum): +class ConnectorEnumType(StrEnum): """ Allowed values of ConnectorCode. """ @@ -522,7 +522,7 @@ class ConnectorType(StrEnum): unknown = "Unknown" -class CostKindType(StrEnum): +class CostKindEnumType(StrEnum): """ CostKindEnumType is used by CommonCostType """ @@ -532,7 +532,7 @@ class CostKindType(StrEnum): renewable_generation_percentage = "RenewableGenerationPercentage" -class CustomerInformationStatusType(StrEnum): +class CustomerInformationStatusEnumType(StrEnum): """ Status in CustomerInformationResponse """ @@ -542,7 +542,7 @@ class CustomerInformationStatusType(StrEnum): invalid = "Invalid" -class DataTransferStatusType(StrEnum): +class DataTransferStatusEnumType(StrEnum): """ Status in DataTransferResponse. """ @@ -553,7 +553,7 @@ class DataTransferStatusType(StrEnum): unknown_vendor_id = "UnknownVendorId" -class DataType(StrEnum): +class DataEnumEnumType(StrEnum): """ DataEnumType is used by CommonVariableCharacteristicsType """ @@ -569,7 +569,7 @@ class DataType(StrEnum): password_string = "passwordString" -class DeleteCertificateStatusType(StrEnum): +class DeleteCertificateStatusEnumType(StrEnum): """ DeleteCertificateStatusEnumType is used by deleteCertificateDeleteCertificateResponse @@ -580,7 +580,7 @@ class DeleteCertificateStatusType(StrEnum): not_found = "NotFound" -class DisplayMessageStatusType(StrEnum): +class DisplayMessageStatusEnumType(StrEnum): """ Result for a SetDisplayMessageRequest as used in a SetDisplayMessageResponse. @@ -594,7 +594,7 @@ class DisplayMessageStatusType(StrEnum): unknown_transaction = "UnknownTransaction" -class EnergyTransferModeType(StrEnum): +class EnergyTransferModeEnumType(StrEnum): """ Enumeration of energy transfer modes. """ @@ -605,7 +605,7 @@ class EnergyTransferModeType(StrEnum): ac_three_phase = "AC_three_phase" -class EventNotificationType(StrEnum): +class EventNotificationEnumType(StrEnum): """ Specifies the event notification type of the message. """ @@ -616,7 +616,7 @@ class EventNotificationType(StrEnum): custom_monitor = "CustomMonitor" -class EventTriggerType(StrEnum): +class EventTriggerEnumType(StrEnum): """ EventTriggerEnumType is used by notifyEventNotifyEventRequest.EventDataType @@ -627,7 +627,7 @@ class EventTriggerType(StrEnum): periodic = "Periodic" -class FirmwareStatusType(StrEnum): +class FirmwareStatusEnumType(StrEnum): """ Status of a firmware download as reported in FirmwareStatusNotificationRequest @@ -649,7 +649,7 @@ class FirmwareStatusType(StrEnum): signature_verified = "SignatureVerified" -class GenericDeviceModelStatusType(StrEnum): +class GenericDeviceModelStatusEnumType(StrEnum): """ Status of a firmware download as reported in GetBaseReportResponse """ @@ -660,7 +660,7 @@ class GenericDeviceModelStatusType(StrEnum): empty_result_set = "EmptyResultSet" -class GenericStatusType(StrEnum): +class GenericStatusEnumType(StrEnum): """ Generic message response status """ @@ -669,7 +669,7 @@ class GenericStatusType(StrEnum): rejected = "Rejected" -class GetCertificateIdUseType(StrEnum): +class GetCertificateIdUseEnumType(StrEnum): v2g_root_certificate = "V2GRootCertificate" mo_root_certificate = "MORootCertificate" csms_root_certificate = "CSMSRootCertificate" @@ -677,7 +677,7 @@ class GetCertificateIdUseType(StrEnum): manufacturer_root_certificate = "ManufacturerRootCertificate" -class GetCertificateStatusType(StrEnum): +class GetCertificateStatusEnumType(StrEnum): """ GetCertificateStatusEnumType is used by getCertificateStatusGetCertificateStatusResponse @@ -687,7 +687,7 @@ class GetCertificateStatusType(StrEnum): failed = "Failed" -class GetChargingProfileStatusType(StrEnum): +class GetChargingProfileStatusEnumType(StrEnum): """ GetChargingProfileStatusEnumType is used by getChargingProfilesGetChargingProfilesResponse @@ -697,7 +697,7 @@ class GetChargingProfileStatusType(StrEnum): no_profiles = "NoProfiles" -class GetDisplayMessagesStatusType(StrEnum): +class GetDisplayMessagesStatusEnumType(StrEnum): """ GetDisplayMessagesStatusEnumType is used by getDisplayMessagesGetDisplayMessagesResponse @@ -707,7 +707,7 @@ class GetDisplayMessagesStatusType(StrEnum): unknown = "Unknown" -class GetInstalledCertificateStatusType(StrEnum): +class GetInstalledCertificateStatusEnumType(StrEnum): """ GetInstalledCertificateStatusEnumType is used by getInstalledCertificateIdsGetInstalledCertificateIdsResponse @@ -717,7 +717,7 @@ class GetInstalledCertificateStatusType(StrEnum): notFound = "NotFound" -class GetVariableStatusType(StrEnum): +class GetVariableStatusEnumType(StrEnum): """ GetVariableStatusEnumType is used by getVariablesGetVariablesResponse.GetVariableResultType @@ -730,7 +730,7 @@ class GetVariableStatusType(StrEnum): not_supported_attribute_type = "NotSupportedAttributeType" -class HashAlgorithmType(StrEnum): +class HashAlgorithmEnumType(StrEnum): """ HashAlgorithmEnumType is used by CommonCertificateHashDataType , CommonOCSPRequestDataType @@ -759,7 +759,7 @@ class IdTokenEnumType(StrEnum): IdTokenType = DeprecatedEnumWrapper(IdTokenEnumType, "IdTokenType") -class InstallCertificateStatusType(StrEnum): +class InstallCertificateStatusEnumType(StrEnum): """ InstallCertificateStatusEnumType is used by installCertificateInstallCertificateResponse @@ -770,7 +770,7 @@ class InstallCertificateStatusType(StrEnum): failed = "Failed" -class InstallCertificateUseType(StrEnum): +class InstallCertificateUseEnumType(StrEnum): """ InstallCertificateUseEnumType is used by installCertificateInstallCertificateRequest @@ -782,7 +782,7 @@ class InstallCertificateUseType(StrEnum): manufacturer_root_certificate = "ManufacturerRootCertificate" -class Iso15118EVCertificateStatusType(StrEnum): +class Iso15118EVCertificateStatusEnumType(StrEnum): """ Iso15118EVCertificateStatusEnumType is used by get15118EVCertificateGet15118EVCertificateResponse @@ -792,7 +792,7 @@ class Iso15118EVCertificateStatusType(StrEnum): failed = "Failed" -class LocationType(StrEnum): +class LocationEnumType(StrEnum): """ Allowable values of the optional "location" field of a value element in SampledValue. @@ -805,7 +805,7 @@ class LocationType(StrEnum): outlet = "Outlet" -class LogType(StrEnum): +class LogEnumType(StrEnum): """ LogEnumType is used by getLogGetLogRequest """ @@ -814,7 +814,7 @@ class LogType(StrEnum): security_log = "SecurityLog" -class LogStatusType(StrEnum): +class LogStatusEnumType(StrEnum): """ Generic message response status """ @@ -824,7 +824,7 @@ class LogStatusType(StrEnum): accepted_canceled = "AcceptedCanceled" -class MeasurandType(StrEnum): +class MeasurandEnumType(StrEnum): """ Allowable values of the optional "measurand" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of @@ -858,7 +858,7 @@ class MeasurandType(StrEnum): voltage = "Voltage" -class MessageFormatType(StrEnum): +class MessageFormatEnumType(StrEnum): """ Format of a message to be displayed on the display of the Charging Station. """ @@ -869,7 +869,7 @@ class MessageFormatType(StrEnum): utf8 = "UTF8" -class MessagePriorityType(StrEnum): +class MessagePriorityEnumType(StrEnum): """ Priority with which a message should be displayed on a Charging Station. """ @@ -879,7 +879,7 @@ class MessagePriorityType(StrEnum): normal_cycle = "NormalCycle" -class MessageStateType(StrEnum): +class MessageStateEnumType(StrEnum): """ State of the Charging Station during which a message SHALL be displayed. """ @@ -889,7 +889,7 @@ class MessageStateType(StrEnum): idle = "Idle" -class MessageTriggerType(StrEnum): +class MessageTriggerEnumType(StrEnum): """ Type of request to be triggered in a TriggerMessage.req """ @@ -910,7 +910,7 @@ class MessageTriggerType(StrEnum): publish_firmware_status_notification = "PublishFirmwareStatusNotification" -class MonitorType(StrEnum): +class MonitorEnumType(StrEnum): """ MonitorEnumType is used by CommonVariableMonitoringType """ @@ -922,7 +922,7 @@ class MonitorType(StrEnum): periodic_clock_aligned = "PeriodicClockAligned" -class MonitorBaseType(StrEnum): +class MonitorBaseEnumType(StrEnum): """ MonitoringBaseEnumType is used by setMonitoringBaseSetMonitoringBaseRequest @@ -933,7 +933,7 @@ class MonitorBaseType(StrEnum): hard_wired_only = "HardWiredOnly" -class MonitoringCriterionType(StrEnum): +class MonitoringCriterionEnumType(StrEnum): """ MonitoringCriterionEnumType is used by getMonitoringReportGetMonitoringReportRequest @@ -944,7 +944,7 @@ class MonitoringCriterionType(StrEnum): periodic_monitoring = "PeriodicMonitoring" -class MutabilityType(StrEnum): +class MutabilityEnumType(StrEnum): """ MutabilityEnumType is used by CommonVariableAttributeType """ @@ -954,7 +954,7 @@ class MutabilityType(StrEnum): read_write = "ReadWrite" -class NotifyEVChargingNeedsStatusType(StrEnum): +class NotifyEVChargingNeedsStatusEnumType(StrEnum): """ Accepted a SASchedule will be provided momentarily. Rejected Servoce is Not Available @@ -966,7 +966,7 @@ class NotifyEVChargingNeedsStatusType(StrEnum): processing = "Processing" -class OCPPInterfaceType(StrEnum): +class OCPPInterfaceEnumType(StrEnum): """ Enumeration of network interfaces. """ @@ -981,7 +981,7 @@ class OCPPInterfaceType(StrEnum): wireless3 = "Wireless3" -class OCPPTransportType(StrEnum): +class OCPPTransportEnumType(StrEnum): """ Enumeration of OCPP transport mechanisms. SOAP is currently not a valid value for OCPP 2.0. @@ -991,7 +991,7 @@ class OCPPTransportType(StrEnum): soap = "SOAP" -class OCPPVersionType(StrEnum): +class OCPPVersionEnumType(StrEnum): """ Enumeration of OCPP transport mechanisms. SOAP is currently not a valid value for OCPP 2.0. @@ -1003,7 +1003,7 @@ class OCPPVersionType(StrEnum): ocpp20 = "OCPP20" -class OperationalStatusType(StrEnum): +class OperationalStatusEnumType(StrEnum): """ Requested availability change in ChangeAvailability.req. """ @@ -1012,7 +1012,7 @@ class OperationalStatusType(StrEnum): operative = "Operative" -class PhaseType(StrEnum): +class PhaseEnumType(StrEnum): """ Phase as used in SampledValue. Phase specifies how a measured value is to be interpreted. Please note that not all values of Phase are applicable to @@ -1031,7 +1031,7 @@ class PhaseType(StrEnum): l3_l1 = "L3-L1" -class PublishFirmwareStatusType(StrEnum): +class PublishFirmwareStatusEnumType(StrEnum): """ Status for when publishing a Firmware """ @@ -1048,7 +1048,7 @@ class PublishFirmwareStatusType(StrEnum): publish_failed = "PublishFailed" -class ReadingContextType(StrEnum): +class ReadingContextEnumType(StrEnum): """ Values of the context field of a value in SampledValue. """ @@ -1063,7 +1063,7 @@ class ReadingContextType(StrEnum): trigger = "Trigger" -class ReasonType(StrEnum): +class ReasonEnumType(StrEnum): """ Reason for stopping a transaction in StopTransactionRequest """ @@ -1089,7 +1089,7 @@ class ReasonType(StrEnum): timeout = "Timeout" -class RecurrencyKindType(StrEnum): +class RecurrencyKindEnumType(StrEnum): """ "Daily" The schedule restarts at the beginning of the next day. "Weekly" The schedule restarts at the beginning of the next week @@ -1100,7 +1100,7 @@ class RecurrencyKindType(StrEnum): weekly = "Weekly" -class RegistrationStatusType(StrEnum): +class RegistrationStatusEnumType(StrEnum): """ Result of registration in response to BootNotification.req. """ @@ -1110,7 +1110,7 @@ class RegistrationStatusType(StrEnum): rejected = "Rejected" -class ReportBaseType(StrEnum): +class ReportBaseEnumType(StrEnum): """ Report Base Type required in GetBaseReportRequest """ @@ -1120,7 +1120,7 @@ class ReportBaseType(StrEnum): summary_inventory = "SummaryInventory" -class RequestStartStopStatusType(StrEnum): +class RequestStartStopStatusEnumType(StrEnum): """ The result of a RemoteStartTransaction.req or RemoteStopTransaction.req request. @@ -1130,12 +1130,12 @@ class RequestStartStopStatusType(StrEnum): rejected = "Rejected" -class ReservationUpdateStatusType(StrEnum): +class ReservationUpdateStatusEnumType(StrEnum): expired = "Expired" removed = "Removed" -class ReserveNowStatusType(StrEnum): +class ReserveNowStatusEnumType(StrEnum): """ Status in ReserveNowResponse. """ @@ -1147,7 +1147,7 @@ class ReserveNowStatusType(StrEnum): unavailable = "Unavailable" -class ResetStatusType(StrEnum): +class ResetStatusEnumType(StrEnum): """ Result of Reset.req """ @@ -1157,7 +1157,7 @@ class ResetStatusType(StrEnum): scheduled = "Scheduled" -class ResetType(StrEnum): +class ResetEnumType(StrEnum): """ Type of reset requested by Reset.req """ @@ -1166,7 +1166,7 @@ class ResetType(StrEnum): on_idle = "OnIdle" -class SendLocalListStatusType(StrEnum): +class SendLocalListStatusEnumType(StrEnum): """ Type of update for a SendLocalList Request. """ @@ -1176,7 +1176,7 @@ class SendLocalListStatusType(StrEnum): version_mismatch = "VersionMismatch" -class SetMonitoringStatusType(StrEnum): +class SetMonitoringStatusEnumType(StrEnum): """ Status in SetVariableMonitoringResponse """ @@ -1189,7 +1189,7 @@ class SetMonitoringStatusType(StrEnum): duplicate = "Duplicate" -class SetNetworkProfileStatusType(StrEnum): +class SetNetworkProfileStatusEnumType(StrEnum): """ Status in SetNetworkProfileResponse """ @@ -1199,7 +1199,7 @@ class SetNetworkProfileStatusType(StrEnum): failed = "Failed" -class SetVariableStatusType(StrEnum): +class SetVariableStatusEnumType(StrEnum): """ Status in ChangeConfigurationResponse. """ @@ -1212,7 +1212,7 @@ class SetVariableStatusType(StrEnum): reboot_required = "RebootRequired" -class TransactionEventType(StrEnum): +class TransactionEventEnumType(StrEnum): """ Type of Event in TransactionEventRequest """ @@ -1222,7 +1222,7 @@ class TransactionEventType(StrEnum): updated = "Updated" -class TriggerMessageStatusType(StrEnum): +class TriggerMessageStatusEnumType(StrEnum): """ Status in TriggerMessageResponse. """ @@ -1232,7 +1232,7 @@ class TriggerMessageStatusType(StrEnum): not_implemented = "NotImplemented" -class TriggerReasonType(StrEnum): +class TriggerReasonEnumType(StrEnum): """ Reason that triggered a transactionEventRequest """ @@ -1260,7 +1260,7 @@ class TriggerReasonType(StrEnum): reset_command = "ResetCommand" -class TxStartStopPointType(StrEnum): +class TxStartStopPointEnumType(StrEnum): """ The values allowed for the TxStartPoint and TxStopPoint variables. """ @@ -1273,7 +1273,7 @@ class TxStartStopPointType(StrEnum): power_path_closed = "PowerPathClosed" -class UnlockStatusType(StrEnum): +class UnlockStatusEnumType(StrEnum): """ Status in response to UnlockConnector.req. """ @@ -1284,7 +1284,7 @@ class UnlockStatusType(StrEnum): unknown_connector = "UnknownConnector" -class UnpublishFirmwareStatusType(StrEnum): +class UnpublishFirmwareStatusEnumType(StrEnum): """ Status for when unpublishing a Firmware (used by UnpublishFirmwareResponse) """ @@ -1294,7 +1294,7 @@ class UnpublishFirmwareStatusType(StrEnum): unpublished = "Unpublished" -class UpdateFirmwareStatusType(StrEnum): +class UpdateFirmwareStatusEnumType(StrEnum): """ Generic message response status for UpdateFirmwareResponse """ @@ -1306,7 +1306,7 @@ class UpdateFirmwareStatusType(StrEnum): revoked_certificate = "RevokedCertificate" -class UpdateType(StrEnum): +class UpdateEnumType(StrEnum): """ Type of update for a SendLocalList Request. """ @@ -1315,7 +1315,7 @@ class UpdateType(StrEnum): full = "Full" -class UploadLogStatusType(StrEnum): +class UploadLogStatusEnumType(StrEnum): """ Status in LogStatusNotificationRequest. """ @@ -1344,7 +1344,7 @@ class VPNType(StrEnum): # DataTypes -class StandardizedUnitsOfMeasureType(StrEnum): +class StandardizedUnitsOfMeasureEnumType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of @@ -1388,11 +1388,11 @@ class StandardizedUnitsOfMeasureType(StrEnum): UnitOfMeasureType = DeprecatedEnumWrapper( - StandardizedUnitsOfMeasureType, "UnitOfMeasureType" + StandardizedUnitsOfMeasureEnumType, "UnitOfMeasureType" ) -class StatusInfoReasonType(StrEnum): +class StatusInfoReasonEnumType(StrEnum): """ Standardized reason codes for StatusInfo defined in Appendix 5. v1.3 """ @@ -1442,7 +1442,7 @@ class StatusInfoReasonType(StrEnum): write_only = "WriteOnly" -class SecurityEventType(StrEnum): +class SecurityEventEnumType(StrEnum): """ Security Events as listed in Appendices (Appendix 1. Security Events) v1.3 """ diff --git a/tests/test_charge_point.py b/tests/test_charge_point.py index 00571f9fd..0ad2daa26 100644 --- a/tests/test_charge_point.py +++ b/tests/test_charge_point.py @@ -26,7 +26,7 @@ NetworkConnectionProfileType, VariableType, ) -from ocpp.v201.enums import OCPPInterfaceType, OCPPTransportType, OCPPVersionType +from ocpp.v201.enums import OCPPInterfaceEnumType, OCPPTransportEnumType, OCPPVersionEnumType def test_getters_should_not_be_called_during_routemap_setup(): @@ -138,12 +138,12 @@ def test_nested_remove_nones(): } connection_data = NetworkConnectionProfileType( - ocpp_version=OCPPVersionType.ocpp20, - ocpp_transport=OCPPTransportType.json, + ocpp_version=OCPPVersionEnumType.ocpp20, + ocpp_transport=OCPPTransportEnumType.json, ocpp_csms_url="wss://localhost:9000", message_timeout=60, security_profile=1, - ocpp_interface=OCPPInterfaceType.wired0, + ocpp_interface=OCPPInterfaceEnumType.wired0, vpn=None, apn=None, ) @@ -328,7 +328,7 @@ def test_serialization_of_collection_of_multiple_elements(): payload = call_result.SetVariables( set_variable_result=[ datatypes.SetVariableResultType( - attribute_status=enums.SetVariableStatusType.accepted, + attribute_status=enums.SetVariableStatusEnumType.accepted, component={ "name": "TemperatureSensor", "instance": "First", diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index 735aa3192..e696d24c4 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -54,35 +54,35 @@ VariableType, ) from ocpp.v201.enums import ( - APNAuthenticationType, - AttributeType, - AuthorizationStatusType, - ChargingProfileKindType, - ChargingProfilePurposeType, - ChargingRateUnitType, - ChargingStateType, - ClearMonitoringStatusType, - CostKindType, - DataType, - EnergyTransferModeType, - EventNotificationType, - EventTriggerType, - HashAlgorithmType, + APNAuthenticationEnumType, + AttributeEnumType, + AuthorizationStatusEnumType, + ChargingProfileKindEnumType, + ChargingProfilePurposeEnumType, + ChargingRateUnitEnumType, + ChargingStateEnumType, + ClearMonitoringStatusEnumType, + CostKindEnumType, + DataEnumEnumType, + EnergyTransferModeEnumType, + EventNotificationEnumType, + EventTriggerEnumType, + HashAlgorithmEnumType, IdTokenEnumType, - LocationType, - MeasurandType, - MessageFormatType, - MonitorType, - MutabilityType, - OCPPInterfaceType, - OCPPTransportType, - OCPPVersionType, - PhaseType, - ReadingContextType, - ReasonType, - SetMonitoringStatusType, - SetVariableStatusType, - StandardizedUnitsOfMeasureType, + LocationEnumType, + MeasurandEnumType, + MessageFormatEnumType, + MonitorEnumType, + MutabilityEnumType, + OCPPInterfaceEnumType, + OCPPTransportEnumType, + OCPPVersionEnumType, + PhaseEnumType, + ReadingContextEnumType, + ReasonEnumType, + SetMonitoringStatusEnumType, + SetVariableStatusEnumType, + StandardizedUnitsOfMeasureEnumType, VPNType, ) @@ -123,7 +123,7 @@ def test_additional_info_type(): def test_apn_type(): at = APNType( apn="internet.example.com", - apn_authentication=APNAuthenticationType.auto, + apn_authentication=APNAuthenticationEnumType.auto, apn_user_name="username", apn_password="password", sim_pin=1234, @@ -145,7 +145,7 @@ def test_apn_type(): def test_authorization_data(): ad = AuthorizationData( id_token_info=IdTokenInfoType( - status=AuthorizationStatusType.accepted, + status=AuthorizationStatusEnumType.accepted, cache_expiry_date_time="2024-01-01T10:00:00Z", charging_priority=1, language_1="en", @@ -248,7 +248,7 @@ def test_charging_limit_type(): def test_charging_needs_type(): cnt = ChargingNeedsType( - requested_energy_transfer=EnergyTransferModeType.dc, + requested_energy_transfer=EnergyTransferModeEnumType.dc, departure_time="2024-01-01T10:00:00Z", ac_charging_parameters=ACChargingParametersType( energy_amount=20, ev_min_current=10, ev_max_current=32, ev_max_voltage=400 @@ -288,7 +288,7 @@ def test_charging_needs_type(): def test_charging_profile_criterion_type(): cpct = ChargingProfileCriterionType( - charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + charging_profile_purpose=ChargingProfilePurposeEnumType.tx_default_profile, stack_level=0, charging_profile_id=[1, 2, 3], ) @@ -304,12 +304,12 @@ def test_charging_profile_type(): cpt = ChargingProfileType( id=1, stack_level=0, - charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, - charging_profile_kind=ChargingProfileKindType.absolute, + charging_profile_purpose=ChargingProfilePurposeEnumType.tx_default_profile, + charging_profile_kind=ChargingProfileKindEnumType.absolute, charging_schedule=[ ChargingScheduleType( id=1, - charging_rate_unit=ChargingRateUnitType.watts, + charging_rate_unit=ChargingRateUnitEnumType.watts, charging_schedule_period=[ ChargingSchedulePeriodType( start_period=0, limit=11000.0, number_phases=3 @@ -371,7 +371,7 @@ def test_charging_station_type(): def test_clear_charging_profile_type(): ccpt = ClearChargingProfileType( evse_id=1, - charging_profile_purpose=ChargingProfilePurposeType.tx_default_profile, + charging_profile_purpose=ChargingProfilePurposeEnumType.tx_default_profile, stack_level=0, ) @@ -384,10 +384,10 @@ def test_clear_charging_profile_type(): def test_clear_monitoring_result_type(): cmrt = ClearMonitoringResultType( - status=ClearMonitoringStatusType.accepted, + status=ClearMonitoringStatusEnumType.accepted, id=123, status_info=StatusInfoType( - reason_code=ReasonType.other, + reason_code=ReasonEnumType.other, additional_info="Successfully cleared monitoring", ), ) @@ -436,7 +436,7 @@ def test_composite_schedule_type(): evse_id=1, duration=3600, schedule_start="2024-01-01T10:00:00Z", - charging_rate_unit=ChargingRateUnitType.watts, + charging_rate_unit=ChargingRateUnitEnumType.watts, charging_schedule_period=[ ChargingSchedulePeriodType(start_period=0, limit=11000.0, number_phases=3) ], @@ -476,7 +476,7 @@ def test_consumption_cost_type(): def test_cost_type(): ct = CostType( - cost_kind=CostKindType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 + cost_kind=CostKindEnumType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 ) new_ct = to_datatype(CostType, ct) @@ -490,14 +490,14 @@ def test_event_data_type(): edt = EventDataType( event_id=1, timestamp="2024-01-01T10:00:00Z", - trigger=EventTriggerType.alerting, + trigger=EventTriggerEnumType.alerting, actual_value="High Temperature", tech_code="TC001", tech_info="Temperature sensor reading high", cleared=False, transaction_id="TX001", variable_monitoring_id=1, - event_notification_type=EventNotificationType.hard_wired_notification, + event_notification_type=EventNotificationEnumType.hard_wired_notification, component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="Temperature", instance="instance1"), ) @@ -542,7 +542,7 @@ def test_get_variable_data_type(): gvdt = GetVariableDataType( component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="CurrentLimit", instance="instance1"), - attribute_type=AttributeType.actual, + attribute_type=AttributeEnumType.actual, ) new_gvdt = to_datatype(GetVariableDataType, gvdt) @@ -559,7 +559,7 @@ def test_get_variable_data_type(): def test_get_variable_result_type(): gvrt = GetVariableResultType( attribute_status="Accepted", - attribute_type=AttributeType.actual, + attribute_type=AttributeEnumType.actual, attribute_value="100", component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="CurrentLimit", instance="instance1"), @@ -585,7 +585,7 @@ def test_id_token_info_type(): language_2="fr", group_id_token=IdTokenEnumType.central, personal_message=MessageContentType( - format=MessageFormatType.ascii, content="Welcome back!", language="en" + format=MessageFormatEnumType.ascii, content="Welcome back!", language="en" ), ) @@ -621,10 +621,10 @@ def test_message_info_type(): id=1, priority=1, message=MessageContentType( - format=MessageFormatType.ascii, content="Important notice", language="en" + format=MessageFormatEnumType.ascii, content="Important notice", language="en" ), display=ComponentType(name="MainDisplay", instance="instance1"), - state=ChargingStateType.charging, + state=ChargingStateEnumType.charging, ) new_mit = to_datatype(MessageInfoType, mit) @@ -644,10 +644,10 @@ def test_meter_value_type(): sampled_value=[ SampledValueType( value=230.0, - context=ReadingContextType.sample_periodic, - measurand=MeasurandType.voltage, - phase=PhaseType.l1, - location=LocationType.outlet, + context=ReadingContextEnumType.sample_periodic, + measurand=MeasurandEnumType.voltage, + phase=PhaseEnumType.l1, + location=LocationEnumType.outlet, ) ], ) @@ -680,7 +680,7 @@ def test_monitoring_data_type(): id=1, transaction=True, value=100.0, - type=MonitorType.upper_threshold, + type=MonitorEnumType.upper_threshold, severity=1, ), ) @@ -698,12 +698,12 @@ def test_monitoring_data_type(): def test_network_connection_profile_type(): ncpt = NetworkConnectionProfileType( - ocpp_version=OCPPVersionType.ocpp20, - ocpp_transport=OCPPTransportType.json, + ocpp_version=OCPPVersionEnumType.ocpp20, + ocpp_transport=OCPPTransportEnumType.json, ocpp_csms_url="wss://example.com/ocpp", message_timeout=30, security_profile=1, - ocpp_interface=OCPPInterfaceType.wired0, + ocpp_interface=OCPPInterfaceEnumType.wired0, vpn=VPNType.ikev2, ) @@ -720,7 +720,7 @@ def test_network_connection_profile_type(): def test_ocsp_request_data_type(): ordt = OCSPRequestDataType( - hash_algorithm=HashAlgorithmType.sha256, + hash_algorithm=HashAlgorithmEnumType.sha256, issuer_name_hash="issuer_hash_value", issuer_key_hash="issuer_key_hash_value", serial_number="serial123", @@ -751,7 +751,7 @@ def test_report_data_type(): variable=VariableType(name="Temperature", instance="instance1"), variable_attribute=[ VariableAttributeType( - type=AttributeType.actual, + type=AttributeEnumType.actual, value="25.5", mutability="ReadWrite", persistent=True, @@ -760,7 +760,7 @@ def test_report_data_type(): ], variable_characteristics=VariableCharacteristicsType( unit="Celsius", - data_type=DataType.decimal, + data_type=DataEnumEnumType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], @@ -835,12 +835,12 @@ def test_sales_tariff_entry_type(): def test_sampled_value_type(): svt = SampledValueType( value=230.0, - context=ReadingContextType.sample_periodic, - measurand=MeasurandType.voltage, - phase=PhaseType.l1, - location=LocationType.outlet, + context=ReadingContextEnumType.sample_periodic, + measurand=MeasurandEnumType.voltage, + phase=PhaseEnumType.l1, + location=LocationEnumType.outlet, unit_of_measure=UnitOfMeasureType( - unit=StandardizedUnitsOfMeasureType.v, multiplier=0 + unit=StandardizedUnitsOfMeasureEnumType.v, multiplier=0 ), ) @@ -859,7 +859,7 @@ def test_sampled_value_type(): def test_set_monitoring_data_type(): smdt = SetMonitoringDataType( value=100.0, - type=MonitorType.upper_threshold, + type=MonitorEnumType.upper_threshold, severity=1, component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="Temperature", instance="instance1"), @@ -882,12 +882,12 @@ def test_set_monitoring_data_type(): def test_set_monitoring_result_type(): smrt = SetMonitoringResultType( - status=SetMonitoringStatusType.accepted, + status=SetMonitoringStatusEnumType.accepted, id=123, status_info=StatusInfoType( - reason_code=ReasonType.other, additional_info="Successfully set monitoring" + reason_code=ReasonEnumType.other, additional_info="Successfully set monitoring" ), - type=MonitorType.upper_threshold, + type=MonitorEnumType.upper_threshold, severity=1, component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="Temperature", instance="instance1"), @@ -912,12 +912,12 @@ def test_set_monitoring_result_type(): def test_set_variable_result_type(): svrt = SetVariableResultType( - attribute_type=AttributeType.actual, - attribute_status=SetVariableStatusType.accepted, + attribute_type=AttributeEnumType.actual, + attribute_status=SetVariableStatusEnumType.accepted, component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="CurrentLimit", instance="instance1"), attribute_status_info=StatusInfoType( - reason_code=ReasonType.other, additional_info="Successfully set variable" + reason_code=ReasonEnumType.other, additional_info="Successfully set variable" ), ) @@ -956,9 +956,9 @@ def test_unit_of_measure_type(): def test_variable_attribute_type(): vat = VariableAttributeType( - type=AttributeType.actual, + type=AttributeEnumType.actual, value="25.5", - mutability=MutabilityType.read_write, + mutability=MutabilityEnumType.read_write, persistent=True, constant=False, ) @@ -975,7 +975,7 @@ def test_variable_attribute_type(): def test_variable_characteristics_type(): vct = VariableCharacteristicsType( unit="Celsius", - data_type=DataType.decimal, + data_type=DataEnumEnumType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], @@ -997,7 +997,7 @@ def test_variable_monitoring_type(): id=1, transaction=True, value=100.0, - type=MonitorType.upper_threshold, + type=MonitorEnumType.upper_threshold, severity=1, ) diff --git a/tests/v201/test_v201_enums.py b/tests/v201/test_v201_enums.py index d717a11aa..0935d6f6d 100644 --- a/tests/v201/test_v201_enums.py +++ b/tests/v201/test_v201_enums.py @@ -1,50 +1,50 @@ -from ocpp.v201.enums import ConnectorType, DataType, TxStartStopPointType +from ocpp.v201.enums import ConnectorEnumType, DataEnumEnumType, TxStartStopPointEnumType def test_connector_type(): - assert ConnectorType.c_ccs1 == "cCCS1" - assert ConnectorType.c_ccs2 == "cCCS2" - assert ConnectorType.c_chao_ji == "cChaoJi" - assert ConnectorType.c_g105 == "cG105" - assert ConnectorType.c_gbt == "cGBT" - assert ConnectorType.c_tesla == "cTesla" - assert ConnectorType.c_type1 == "cType1" - assert ConnectorType.c_type2 == "cType2" - assert ConnectorType.s309_1p_16a == "s309-1P-16A" - assert ConnectorType.s309_1p_32a == "s309-1P-32A" - assert ConnectorType.s309_3p_16a == "s309-3P-16A" - assert ConnectorType.s309_3p_32a == "s309-3P-32A" - assert ConnectorType.s_bs1361 == "sBS1361" - assert ConnectorType.s_cee_7_7 == "sCEE-7-7" - assert ConnectorType.s_type2 == "sType2" - assert ConnectorType.s_type3 == "sType3" - assert ConnectorType.opp_charge == "OppCharge" - assert ConnectorType.other_1ph_max_16a == "Other1PhMax16A" - assert ConnectorType.other_1ph_over_16a == "Other1PhOver16A" - assert ConnectorType.other_3ph == "Other3Ph" - assert ConnectorType.pan == "Pan" - assert ConnectorType.w_inductive == "wInductive" - assert ConnectorType.w_resonant == "wResonant" - assert ConnectorType.undetermined == "Undetermined" - assert ConnectorType.unknown == "Unknown" + assert ConnectorEnumType.c_ccs1 == "cCCS1" + assert ConnectorEnumType.c_ccs2 == "cCCS2" + assert ConnectorEnumType.c_chao_ji == "cChaoJi" + assert ConnectorEnumType.c_g105 == "cG105" + assert ConnectorEnumType.c_gbt == "cGBT" + assert ConnectorEnumType.c_tesla == "cTesla" + assert ConnectorEnumType.c_type1 == "cType1" + assert ConnectorEnumType.c_type2 == "cType2" + assert ConnectorEnumType.s309_1p_16a == "s309-1P-16A" + assert ConnectorEnumType.s309_1p_32a == "s309-1P-32A" + assert ConnectorEnumType.s309_3p_16a == "s309-3P-16A" + assert ConnectorEnumType.s309_3p_32a == "s309-3P-32A" + assert ConnectorEnumType.s_bs1361 == "sBS1361" + assert ConnectorEnumType.s_cee_7_7 == "sCEE-7-7" + assert ConnectorEnumType.s_type2 == "sType2" + assert ConnectorEnumType.s_type3 == "sType3" + assert ConnectorEnumType.opp_charge == "OppCharge" + assert ConnectorEnumType.other_1ph_max_16a == "Other1PhMax16A" + assert ConnectorEnumType.other_1ph_over_16a == "Other1PhOver16A" + assert ConnectorEnumType.other_3ph == "Other3Ph" + assert ConnectorEnumType.pan == "Pan" + assert ConnectorEnumType.w_inductive == "wInductive" + assert ConnectorEnumType.w_resonant == "wResonant" + assert ConnectorEnumType.undetermined == "Undetermined" + assert ConnectorEnumType.unknown == "Unknown" def test_data_type(): - assert DataType.string == "string" - assert DataType.decimal == "decimal" - assert DataType.integer == "integer" - assert DataType.date_time == "dateTime" - assert DataType.boolean == "boolean" - assert DataType.option_list == "OptionList" - assert DataType.sequence_list == "SequenceList" - assert DataType.member_list == "MemberList" - assert DataType.password_string == "passwordString" + assert DataEnumEnumType.string == "string" + assert DataEnumEnumType.decimal == "decimal" + assert DataEnumEnumType.integer == "integer" + assert DataEnumEnumType.date_time == "dateTime" + assert DataEnumEnumType.boolean == "boolean" + assert DataEnumEnumType.option_list == "OptionList" + assert DataEnumEnumType.sequence_list == "SequenceList" + assert DataEnumEnumType.member_list == "MemberList" + assert DataEnumEnumType.password_string == "passwordString" def test_tx_start_stop_point(): - assert TxStartStopPointType.authorized == "Authorized" - assert TxStartStopPointType.data_signed == "DataSigned" - assert TxStartStopPointType.energy_transfer == "EnergyTransfer" - assert TxStartStopPointType.ev_connected == "EVConnected" - assert TxStartStopPointType.parking_bay_occupancy == "ParkingBayOccupancy" - assert TxStartStopPointType.power_path_closed == "PowerPathClosed" + assert TxStartStopPointEnumType.authorized == "Authorized" + assert TxStartStopPointEnumType.data_signed == "DataSigned" + assert TxStartStopPointEnumType.energy_transfer == "EnergyTransfer" + assert TxStartStopPointEnumType.ev_connected == "EVConnected" + assert TxStartStopPointEnumType.parking_bay_occupancy == "ParkingBayOccupancy" + assert TxStartStopPointEnumType.power_path_closed == "PowerPathClosed" From c27e55a4832ed9d7dd0c501c92f574e66f861f3e Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 10:49:47 -0500 Subject: [PATCH 21/27] UnitOfMeasureType can use a value from the standardized list or a custom string, as per the specs in 2.49 --- ocpp/v201/datatypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 68255f702..d25d04f57 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Optional +from typing import List, Optional, Union from ocpp.v201 import enums @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[enums.StandardizedUnitsOfMeasureEnumType] = None + unit: Optional[Union[enums.StandardizedUnitsOfMeasureEnumType, str]] = None multiplier: Optional[int] = None From 8cdd774d69f469c1de108d53c710d944f2afec55 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 11:34:18 -0500 Subject: [PATCH 22/27] fixing EnumEnum in datatype, correct formatting errors --- ocpp/v201/datatypes.py | 2 +- ocpp/v201/enums.py | 2 +- tests/test_charge_point.py | 6 +++++- tests/v201/test_v201_data_types.py | 20 +++++++++++++------- tests/v201/test_v201_enums.py | 20 ++++++++++---------- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index d25d04f57..4150dc0f4 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -713,7 +713,7 @@ class VariableCharacteristicsType: VariableCharacteristicsType is used by: NotifyReportRequest.ReportDataType """ - data_type: enums.DataEnumEnumType + data_type: enums.DataEnumType supports_monitoring: bool unit: Optional[str] = None min_limit: Optional[float] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 01c3f6a84..3d6fd1288 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -553,7 +553,7 @@ class DataTransferStatusEnumType(StrEnum): unknown_vendor_id = "UnknownVendorId" -class DataEnumEnumType(StrEnum): +class DataEnumType(StrEnum): """ DataEnumType is used by CommonVariableCharacteristicsType """ diff --git a/tests/test_charge_point.py b/tests/test_charge_point.py index 0ad2daa26..074b4afd7 100644 --- a/tests/test_charge_point.py +++ b/tests/test_charge_point.py @@ -26,7 +26,11 @@ NetworkConnectionProfileType, VariableType, ) -from ocpp.v201.enums import OCPPInterfaceEnumType, OCPPTransportEnumType, OCPPVersionEnumType +from ocpp.v201.enums import ( + OCPPInterfaceEnumType, + OCPPTransportEnumType, + OCPPVersionEnumType, +) def test_getters_should_not_be_called_during_routemap_setup(): diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index e696d24c4..c801a3ab8 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -63,7 +63,7 @@ ChargingStateEnumType, ClearMonitoringStatusEnumType, CostKindEnumType, - DataEnumEnumType, + DataEnumType, EnergyTransferModeEnumType, EventNotificationEnumType, EventTriggerEnumType, @@ -476,7 +476,9 @@ def test_consumption_cost_type(): def test_cost_type(): ct = CostType( - cost_kind=CostKindEnumType.carbon_dioxide_emission, amount=1.0, amount_multiplier=0 + cost_kind=CostKindEnumType.carbon_dioxide_emission, + amount=1.0, + amount_multiplier=0, ) new_ct = to_datatype(CostType, ct) @@ -621,7 +623,9 @@ def test_message_info_type(): id=1, priority=1, message=MessageContentType( - format=MessageFormatEnumType.ascii, content="Important notice", language="en" + format=MessageFormatEnumType.ascii, + content="Important notice", + language="en", ), display=ComponentType(name="MainDisplay", instance="instance1"), state=ChargingStateEnumType.charging, @@ -760,7 +764,7 @@ def test_report_data_type(): ], variable_characteristics=VariableCharacteristicsType( unit="Celsius", - data_type=DataEnumEnumType.decimal, + data_type=DataEnumType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], @@ -885,7 +889,8 @@ def test_set_monitoring_result_type(): status=SetMonitoringStatusEnumType.accepted, id=123, status_info=StatusInfoType( - reason_code=ReasonEnumType.other, additional_info="Successfully set monitoring" + reason_code=ReasonEnumType.other, + additional_info="Successfully set monitoring", ), type=MonitorEnumType.upper_threshold, severity=1, @@ -917,7 +922,8 @@ def test_set_variable_result_type(): component=ComponentType(name="MainController", instance="instance1"), variable=VariableType(name="CurrentLimit", instance="instance1"), attribute_status_info=StatusInfoType( - reason_code=ReasonEnumType.other, additional_info="Successfully set variable" + reason_code=ReasonEnumType.other, + additional_info="Successfully set variable", ), ) @@ -975,7 +981,7 @@ def test_variable_attribute_type(): def test_variable_characteristics_type(): vct = VariableCharacteristicsType( unit="Celsius", - data_type=DataEnumEnumType.decimal, + data_type=DataEnumType.decimal, min_limit="-20", max_limit="50", values_list=["10", "20", "30"], diff --git a/tests/v201/test_v201_enums.py b/tests/v201/test_v201_enums.py index 0935d6f6d..ce26e6576 100644 --- a/tests/v201/test_v201_enums.py +++ b/tests/v201/test_v201_enums.py @@ -1,4 +1,4 @@ -from ocpp.v201.enums import ConnectorEnumType, DataEnumEnumType, TxStartStopPointEnumType +from ocpp.v201.enums import ConnectorEnumType, DataEnumType, TxStartStopPointEnumType def test_connector_type(): @@ -30,15 +30,15 @@ def test_connector_type(): def test_data_type(): - assert DataEnumEnumType.string == "string" - assert DataEnumEnumType.decimal == "decimal" - assert DataEnumEnumType.integer == "integer" - assert DataEnumEnumType.date_time == "dateTime" - assert DataEnumEnumType.boolean == "boolean" - assert DataEnumEnumType.option_list == "OptionList" - assert DataEnumEnumType.sequence_list == "SequenceList" - assert DataEnumEnumType.member_list == "MemberList" - assert DataEnumEnumType.password_string == "passwordString" + assert DataEnumType.string == "string" + assert DataEnumType.decimal == "decimal" + assert DataEnumType.integer == "integer" + assert DataEnumType.date_time == "dateTime" + assert DataEnumType.boolean == "boolean" + assert DataEnumType.option_list == "OptionList" + assert DataEnumType.sequence_list == "SequenceList" + assert DataEnumType.member_list == "MemberList" + assert DataEnumType.password_string == "passwordString" def test_tx_start_stop_point(): From 69971aebbb73f1be55a1d9d8669dc9e043f77d68 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 12:43:38 -0500 Subject: [PATCH 23/27] enum fixes for : TxCtrlrVariableName, ChargingStationVariableName, LocalEnergeStorageVariableName, ConnectedEVVariableName, StandardizedVariableName, InvalidMessageSeq, Bytes --- ocpp/v201/enums.py | 55 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 3d6fd1288..4e49f5d7b 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -1353,7 +1353,7 @@ class StandardizedUnitsOfMeasureEnumType(StrEnum): """ asu = "ASU" - b = "Bytes" + b = "B" db = "dB" dbm = "dBm" deg = "Deg" @@ -1406,7 +1406,7 @@ class StatusInfoReasonEnumType(StrEnum): invalid_certificate = "InvalidCertificate" invalid_csr = "InvalidCSR" invalid_id_token = "InvalidIdToken" - invalid_message_sequence = "InvalidMessageSequence" + invalid_message_sequence = "InvalidMessageSeq" invalid_profile = "InvalidProfile" invalid_schedule = "InvalidSchedule" invalid_stack_level = "InvalidStackLevel" @@ -1564,7 +1564,7 @@ class PhysicalComponentName(StrEnum): vehicle_id_sensor = "VehicleIdSensor" -class GenericVariableName(StrEnum): +class StandardizedVariableName(StrEnum): """ Variable names where the component type is non-specific derived from a union of in appendices_CSV_v1.3.zip, @@ -1620,6 +1620,7 @@ class GenericVariableName(StrEnum): impedance = "Impedance" imsi = "IMSI" interval = "Interval" + iso_15118_evse_id = "ISO15118EvseId" length = "Length" light = "Light" manufacturer = "Manufacturer" @@ -1995,7 +1996,6 @@ class TxCtrlrVariableName(StrEnum): See ControllerComponentName for referenced logical component """ - charging_time = "ChargingTime" ev_connection_time_out = "EVConnectionTimeOut" max_energy_on_invalid_id = "MaxEnergyOnInvalidId" stop_tx_on_ev_side_disconnect = "StopTxOnEVSideDisconnect" @@ -2148,7 +2148,6 @@ class ChargingStationVariableName(StrEnum): current_imbalance = "CurrentImbalance" ec_variant = "ECVariant" enabled = "Enabled" - identity = "Identity" model = "Model" operating_times = "OperatingTimes" overload = "Overload" @@ -2179,27 +2178,50 @@ class ConnectedEVVariableName(StrEnum): Variable names where the component type is ConnectedEV See PhysicalComponentName for referenced physical component """ + available = "Available" - protocol_agreed = "ProtocolAgreed" - protocol_supported_by_ev = "ProtocolSupportedByEV" + # Vehicle vehicle_id = "VehicleId" + protocol_agreed = "ProtocolAgreed" + protocol_supported_by_e_v = "ProtocolSupportedByEV" + # Voltage and current values - ac_current = "ACCurrent" - ac_voltage = "ACVoltage" - dc_current = "DCCurrent" - dc_voltage = "DCVoltage" + ac_current_min_set = "ACCurrent.minSet" + ac_current_max_set = "ACCurrent.maxSet" + ac_voltage_max_set = "ACVoltage.maxSet" + dc_current_min_set = "DCCurrent.minSet" + dc_current_max_set = "DCCurrent.maxSet" + dc_current_target = "DCCurrent.target" + dc_voltage_min_set = "DCVoltage.minSet" + dc_voltage_max_set = "DCVoltage.maxSet" + dc_voltage_target = "DCVoltage.target" + # Power, energy and time values - power = "Power" - energy_import = "EnergyImport" - departure_time = "DepartureTime" + power_max_set = "Power.maxSet" energy_capacity = "EnergyCapacity" + energy_import_target = "EnergyImport.target" + departure_time = "DepartureTime" remaining_time_bulk = "RemainingTimeBulk" - remaining_time_full = "RemainingTimeFull" - state_of_charge = "StateOfCharge" + remaining_time_full_max_set = "RemainingTimeFull.maxSet" + remaining_time_full_actual = "RemainingTimeFull.actual" state_of_charge_bulk = "StateOfChargeBulk" + state_of_charge_max_set = "StateOfCharge.maxSet" + state_of_charge_actual = "StateOfCharge.actual" charging_complete_bulk = "ChargingCompleteBulk" charging_complete_full = "ChargingCompleteFull" + # Status values + battery_over_voltage = " BatteryOvervoltage" + battery_under_voltage = " BatteryUndervoltage" + charging_current_deviation = " ChargingCurrentDeviation" + battery_temperature = "BatteryTemperature" + voltage_deviation = "VoltageDeviation" + charging_system_error = "ChargingSystemError" + vehicle_shift_position = "VehicleShiftPosition" + vehicle_charging_enabled = "VehicleChargingEnabled" + charging_system_incompatibility = "ChargingSystemIncompatibility" + charger_connector_lock_fault = "ChargerConnectorLockFault" + class ChargingStateVariableName(StrEnum): """ @@ -2629,7 +2651,6 @@ class LocalEnergyStorageVariableName(StrEnum): See PhysicalComponentName for referenced physical component """ - capacity = "Capacity" energy_capacity = "EnergyCapacity" identity = "Identity" From db335bb515fd4d00e68b63c9e69ddf0e3e85fac0 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 13:01:33 -0500 Subject: [PATCH 24/27] fix formatting issue --- ocpp/v201/enums.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 4e49f5d7b..cb3bfad84 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -2178,6 +2178,7 @@ class ConnectedEVVariableName(StrEnum): Variable names where the component type is ConnectedEV See PhysicalComponentName for referenced physical component """ + available = "Available" # Vehicle From f616705cd9ff0e08b60b82d1c93c1c362ae0e583 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Thu, 12 Dec 2024 13:34:39 -0500 Subject: [PATCH 25/27] naming change --- ocpp/v201/enums.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index cb3bfad84..e9a2cbb30 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -2184,7 +2184,7 @@ class ConnectedEVVariableName(StrEnum): # Vehicle vehicle_id = "VehicleId" protocol_agreed = "ProtocolAgreed" - protocol_supported_by_e_v = "ProtocolSupportedByEV" + protocol_supported_by_ev = "ProtocolSupportedByEV" # Voltage and current values ac_current_min_set = "ACCurrent.minSet" From ff1e071740c9878c7e53a56a1d5c9d36af378215 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Fri, 13 Dec 2024 11:24:21 -0500 Subject: [PATCH 26/27] changes based on PR feedback --- ocpp/v201/call_result.py | 2 +- ocpp/v201/datatypes.py | 4 +-- ocpp/v201/enums.py | 44 ++++++------------------------ tests/v201/test_v201_data_types.py | 8 +++--- 4 files changed, 15 insertions(+), 43 deletions(-) diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index f603b1cba..0150f207f 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -334,7 +334,7 @@ class SendLocalList: @dataclass class SetChargingProfile: - status: enums.ChargingProfileStatus + status: enums.ChargingProfileStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/datatypes.py b/ocpp/v201/datatypes.py index 4150dc0f4..a2e650289 100644 --- a/ocpp/v201/datatypes.py +++ b/ocpp/v201/datatypes.py @@ -555,7 +555,7 @@ class UnitOfMeasureType: UnitOfMeasureType is used by: SampledValueType """ - unit: Optional[Union[enums.StandardizedUnitsOfMeasureEnumType, str]] = None + unit: Optional[Union[enums.StandardizedUnitsOfMeasureType, str]] = None multiplier: Optional[int] = None @@ -642,7 +642,7 @@ class VPNType: user: str password: str key: str - type: enums.VPNType + type: enums.VPNEnumType group: Optional[str] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index e9a2cbb30..12e19d05f 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -10,26 +10,6 @@ class StrEnum(str, Enum): # pragma: no cover pass # pragma: no cover -class DeprecatedEnumWrapper: - """ - Since enums can't be subclassed in order to add a deprecation warning, - this class is included to help warn users of deprecated enums. - """ - - def __init__(self, enum_class, alias_name): - self.enum_class = enum_class - self.alias_name = alias_name - - def __getattr__(self, name): - warn( - ( - f"Enum '{self.alias_name}' is deprecated, " - + "instead use '{self.enum_class.__name__}'" - ) - ) - return getattr(self.enum_class, name) - - class Action(StrEnum): """An Action is a required part of a Call message.""" @@ -365,7 +345,7 @@ class ChargingProfilePurposeEnumType(StrEnum): tx_profile = "TxProfile" -class ChargingProfileStatus(StrEnum): +class ChargingProfileStatusEnumType(StrEnum): """ Status returned in response to SetChargingProfile.req. """ @@ -756,9 +736,6 @@ class IdTokenEnumType(StrEnum): no_authorization = "NoAuthorization" -IdTokenType = DeprecatedEnumWrapper(IdTokenEnumType, "IdTokenType") - - class InstallCertificateStatusEnumType(StrEnum): """ InstallCertificateStatusEnumType is used by @@ -1330,7 +1307,7 @@ class UploadLogStatusEnumType(StrEnum): accepted_canceled = "AcceptedCanceled" -class VPNType(StrEnum): +class VPNEnumType(StrEnum): """ Enumeration of VPN Types used in SetNetworkProfileRequest.VPNType """ @@ -1344,7 +1321,7 @@ class VPNType(StrEnum): # DataTypes -class StandardizedUnitsOfMeasureEnumType(StrEnum): +class StandardizedUnitsOfMeasureType(StrEnum): """ Allowable values of the optional "unit" field of a Value element, as used in MeterValues.req and StopTransaction.req messages. Default value of @@ -1387,12 +1364,7 @@ class StandardizedUnitsOfMeasureEnumType(StrEnum): k = "K" -UnitOfMeasureType = DeprecatedEnumWrapper( - StandardizedUnitsOfMeasureEnumType, "UnitOfMeasureType" -) - - -class StatusInfoReasonEnumType(StrEnum): +class StatusInfoReasonType(StrEnum): """ Standardized reason codes for StatusInfo defined in Appendix 5. v1.3 """ @@ -1442,7 +1414,7 @@ class StatusInfoReasonEnumType(StrEnum): write_only = "WriteOnly" -class SecurityEventEnumType(StrEnum): +class SecurityEventType(StrEnum): """ Security Events as listed in Appendices (Appendix 1. Security Events) v1.3 """ @@ -1620,7 +1592,7 @@ class StandardizedVariableName(StrEnum): impedance = "Impedance" imsi = "IMSI" interval = "Interval" - iso_15118_evse_id = "ISO15118EvseId" + iso15118_evse_id = "ISO15118EvseId" length = "Length" light = "Light" manufacturer = "Manufacturer" @@ -2212,8 +2184,8 @@ class ConnectedEVVariableName(StrEnum): charging_complete_full = "ChargingCompleteFull" # Status values - battery_over_voltage = " BatteryOvervoltage" - battery_under_voltage = " BatteryUndervoltage" + battery_overvoltage = " BatteryOvervoltage" + battery_undervoltage = " BatteryUndervoltage" charging_current_deviation = " ChargingCurrentDeviation" battery_temperature = "BatteryTemperature" voltage_deviation = "VoltageDeviation" diff --git a/tests/v201/test_v201_data_types.py b/tests/v201/test_v201_data_types.py index c801a3ab8..30cffc552 100644 --- a/tests/v201/test_v201_data_types.py +++ b/tests/v201/test_v201_data_types.py @@ -82,8 +82,8 @@ ReasonEnumType, SetMonitoringStatusEnumType, SetVariableStatusEnumType, - StandardizedUnitsOfMeasureEnumType, - VPNType, + StandardizedUnitsOfMeasureType, + VPNEnumType, ) T = TypeVar("T", bound="dataclass") @@ -708,7 +708,7 @@ def test_network_connection_profile_type(): message_timeout=30, security_profile=1, ocpp_interface=OCPPInterfaceEnumType.wired0, - vpn=VPNType.ikev2, + vpn=VPNEnumType.ikev2, ) new_ncpt = to_datatype(NetworkConnectionProfileType, ncpt) @@ -844,7 +844,7 @@ def test_sampled_value_type(): phase=PhaseEnumType.l1, location=LocationEnumType.outlet, unit_of_measure=UnitOfMeasureType( - unit=StandardizedUnitsOfMeasureEnumType.v, multiplier=0 + unit=StandardizedUnitsOfMeasureType.v, multiplier=0 ), ) From 635b5e8240a488496307930413aebe4af335c739 Mon Sep 17 00:00:00 2001 From: Andrew Mirsky Date: Wed, 18 Dec 2024 09:45:37 -0500 Subject: [PATCH 27/27] removing spaces in ConnectedEVVariableName. and fixing types in SetMonitoringBase and PublishFirmwareResponse --- ocpp/v201/call_result.py | 4 ++-- ocpp/v201/enums.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ocpp/v201/call_result.py b/ocpp/v201/call_result.py index 0150f207f..c4e78326c 100644 --- a/ocpp/v201/call_result.py +++ b/ocpp/v201/call_result.py @@ -271,7 +271,7 @@ class NotifyReport: @dataclass class PublishFirmware: - status: enums.PublishFirmwareStatusEnumType + status: enums.GenericStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None @@ -348,7 +348,7 @@ class SetDisplayMessage: @dataclass class SetMonitoringBase: - status: enums.GenericStatusEnumType + status: enums.GenericDeviceModelStatusEnumType status_info: Optional[datatypes.StatusInfoType] = None custom_data: Optional[Dict[str, Any]] = None diff --git a/ocpp/v201/enums.py b/ocpp/v201/enums.py index 12e19d05f..44a634c2d 100644 --- a/ocpp/v201/enums.py +++ b/ocpp/v201/enums.py @@ -2184,9 +2184,9 @@ class ConnectedEVVariableName(StrEnum): charging_complete_full = "ChargingCompleteFull" # Status values - battery_overvoltage = " BatteryOvervoltage" - battery_undervoltage = " BatteryUndervoltage" - charging_current_deviation = " ChargingCurrentDeviation" + battery_overvoltage = "BatteryOvervoltage" + battery_undervoltage = "BatteryUndervoltage" + charging_current_deviation = "ChargingCurrentDeviation" battery_temperature = "BatteryTemperature" voltage_deviation = "VoltageDeviation" charging_system_error = "ChargingSystemError"