// @generated by ocpp-codegen from schemas/. Do not edit by hand -- run
// `scripts/generate.sh` to regenerate; manual changes will be overwritten.
/// This class does not get 'AdditionalProperties = false' in the schema generation, so it can be extended with arbitrary JSON properties to allow adding custom data.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CustomData {
#[cfg_attr(feature = "serde", serde(rename = "vendorId"))]
pub vendor_id: heapless::String<255usize>,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CustomData {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GenericStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GenericStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Element providing more information about the status.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StatusInfo<CustomDataType = crate::NoCustomData> {
/// Additional text to provide detailed information.
#[cfg_attr(feature = "serde", serde(rename = "additionalInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_info: Option<alloc::string::String>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// A predefined code for the reason why the status is returned in this response. The string is case-insensitive.
#[cfg_attr(feature = "serde", serde(rename = "reasonCode"))]
pub reason_code: heapless::String<20usize>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for StatusInfo<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_info {
crate::validate::check_max_length(value, 1024usize)
.map_err(|error| error.in_field("additionalInfo"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Element providing more information about the status.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StatusInfo<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
> {
/// Additional text to provide detailed information.
#[cfg_attr(feature = "serde", serde(rename = "additionalInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_info: Option<heapless::String<STATUS_INFO_ADDITIONAL_INFO_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// A predefined code for the reason why the status is returned in this response. The string is case-insensitive.
#[cfg_attr(feature = "serde", serde(rename = "reasonCode"))]
pub reason_code: heapless::String<20usize>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
> crate::validate::Validate
for StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_info {
crate::validate::check_max_length(value, 1024usize)
.map_err(|error| error.in_field("additionalInfo"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PeriodicEventStreamParams<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Time in seconds after which stream data is sent.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub interval: Option<i64>,
/// Number of items to be sent together in stream.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub values: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for PeriodicEventStreamParams<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.interval {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("interval"))?;
}
if let Some(value) = self.values {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("values"))?;
}
Ok(())
}
}
/// Contains a case insensitive identifier to use for the authorization and the type of authorization to support multiple forms of identifiers.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AdditionalInfo<CustomDataType = crate::NoCustomData> {
/// *(2.1)* This field specifies the additional IdToken.
#[cfg_attr(feature = "serde", serde(rename = "additionalIdToken"))]
pub additional_id_token: heapless::String<255usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// _additionalInfo_ can be used to send extra information to CSMS in addition to the regular authorization with _IdToken_. _AdditionalInfo_ contains one or more custom _types_, which need to be agreed upon by all parties involved. When the _type_ is not supported, the CSMS/Charging Station MAY ignore the _additionalInfo_.
pub r#type: heapless::String<50usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for AdditionalInfo<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Contains a case insensitive identifier to use for the authorization and the type of authorization to support multiple forms of identifiers.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IdToken<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "additionalInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_info: Option<alloc::vec::Vec<AdditionalInfo<CustomDataType>>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* IdToken is case insensitive. Might hold the hidden id of an RFID tag, but can for example also contain a UUID.
#[cfg_attr(feature = "serde", serde(rename = "idToken"))]
pub id_token: heapless::String<255usize>,
/// *(2.1)* Enumeration of possible idToken types. Values defined in Appendix as IdTokenEnumStringType.
pub r#type: heapless::String<20usize>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for IdToken<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_info {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("additionalInfo"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("additionalInfo"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Contains a case insensitive identifier to use for the authorization and the type of authorization to support multiple forms of identifiers.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IdToken<
CustomDataType = crate::NoCustomData,
const ID_TOKEN_ADDITIONAL_INFO_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "additionalInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_info: Option<
heapless::Vec<AdditionalInfo<CustomDataType>, ID_TOKEN_ADDITIONAL_INFO_CAP>,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* IdToken is case insensitive. Might hold the hidden id of an RFID tag, but can for example also contain a UUID.
#[cfg_attr(feature = "serde", serde(rename = "idToken"))]
pub id_token: heapless::String<255usize>,
/// *(2.1)* Enumeration of possible idToken types. Values defined in Appendix as IdTokenEnumStringType.
pub r#type: heapless::String<20usize>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const ID_TOKEN_ADDITIONAL_INFO_CAP: usize> crate::validate::Validate
for IdToken<CustomDataType, ID_TOKEN_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_info {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("additionalInfo"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("additionalInfo"))?;
}
}
Ok(())
}
}
/// Used algorithms for the hashes provided.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum HashAlgorithmEnum {
SHA256,
SHA384,
SHA512,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for HashAlgorithmEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Information about a certificate for an OCSP check.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OCSPRequestData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "hashAlgorithm"))]
pub hash_algorithm: HashAlgorithmEnum,
/// The hash of the DER encoded public key:
/// the value (excluding tag and length) of the subject
/// public key field in the issuer’s certificate.
#[cfg_attr(feature = "serde", serde(rename = "issuerKeyHash"))]
pub issuer_key_hash: heapless::String<128usize>,
/// The hash of the issuer’s distinguished
/// name (DN), that must be calculated over the DER
/// encoding of the issuer’s name field in the certificate
/// being checked.
#[cfg_attr(feature = "serde", serde(rename = "issuerNameHash"))]
pub issuer_name_hash: heapless::String<128usize>,
/// This contains the responder URL (Case insensitive).
#[cfg_attr(feature = "serde", serde(rename = "responderURL"))]
pub responder_u_r_l: alloc::string::String,
/// The string representation of the
/// hexadecimal value of the serial number without the
/// prefix "0x" and without leading zeroes.
#[cfg_attr(feature = "serde", serde(rename = "serialNumber"))]
pub serial_number: heapless::String<40usize>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for OCSPRequestData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.hash_algorithm)
.map_err(|error| error.in_field("hashAlgorithm"))?;
crate::validate::check_max_length(&self.responder_u_r_l, 2000usize)
.map_err(|error| error.in_field("responderURL"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Information about a certificate for an OCSP check.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OCSPRequestData<
CustomDataType = crate::NoCustomData,
const O_C_S_P_REQUEST_DATA_RESPONDER_U_R_L_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "hashAlgorithm"))]
pub hash_algorithm: HashAlgorithmEnum,
/// The hash of the DER encoded public key:
/// the value (excluding tag and length) of the subject
/// public key field in the issuer’s certificate.
#[cfg_attr(feature = "serde", serde(rename = "issuerKeyHash"))]
pub issuer_key_hash: heapless::String<128usize>,
/// The hash of the issuer’s distinguished
/// name (DN), that must be calculated over the DER
/// encoding of the issuer’s name field in the certificate
/// being checked.
#[cfg_attr(feature = "serde", serde(rename = "issuerNameHash"))]
pub issuer_name_hash: heapless::String<128usize>,
/// This contains the responder URL (Case insensitive).
#[cfg_attr(feature = "serde", serde(rename = "responderURL"))]
pub responder_u_r_l: heapless::String<O_C_S_P_REQUEST_DATA_RESPONDER_U_R_L_CAP>,
/// The string representation of the
/// hexadecimal value of the serial number without the
/// prefix "0x" and without leading zeroes.
#[cfg_attr(feature = "serde", serde(rename = "serialNumber"))]
pub serial_number: heapless::String<40usize>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const O_C_S_P_REQUEST_DATA_RESPONDER_U_R_L_CAP: usize,
> crate::validate::Validate
for OCSPRequestData<CustomDataType, O_C_S_P_REQUEST_DATA_RESPONDER_U_R_L_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.hash_algorithm)
.map_err(|error| error.in_field("hashAlgorithm"))?;
crate::validate::check_max_length(&self.responder_u_r_l, 2000usize)
.map_err(|error| error.in_field("responderURL"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EnergyTransferModeEnum {
#[cfg_attr(feature = "serde", serde(rename = "AC_single_phase"))]
ACsinglephase,
#[cfg_attr(feature = "serde", serde(rename = "AC_two_phase"))]
ACtwophase,
#[cfg_attr(feature = "serde", serde(rename = "AC_three_phase"))]
ACthreephase,
DC,
#[cfg_attr(feature = "serde", serde(rename = "AC_BPT"))]
ACBPT,
#[cfg_attr(feature = "serde", serde(rename = "AC_BPT_DER"))]
ACBPTDER,
#[cfg_attr(feature = "serde", serde(rename = "AC_DER"))]
ACDER,
#[cfg_attr(feature = "serde", serde(rename = "DC_BPT"))]
DCBPT,
#[cfg_attr(feature = "serde", serde(rename = "DC_ACDP"))]
DCACDP,
#[cfg_attr(feature = "serde", serde(rename = "DC_ACDP_BPT"))]
DCACDPBPT,
WPT,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for EnergyTransferModeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Certificate status information.
/// - if all certificates are valid: return 'Accepted'.
/// - if one of the certificates was revoked, return 'CertificateRevoked'.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AuthorizeCertificateStatusEnum {
Accepted,
SignatureError,
CertificateExpired,
CertificateRevoked,
NoCertificateAvailable,
CertChainError,
ContractCancelled,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for AuthorizeCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Format of the message.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MessageFormatEnum {
ASCII,
HTML,
URI,
UTF8,
QRCODE,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MessageFormatEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MessageContent<CustomDataType = crate::NoCustomData> {
/// *(2.1)* Required. Message contents. +
/// Maximum length supported by Charging Station is given in OCPPCommCtrlr.FieldLength\["MessageContentType.content"\].
/// Maximum length defaults to 1024.
pub content: alloc::string::String,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub format: MessageFormatEnum,
/// Message language identifier. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language: Option<heapless::String<8usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for MessageContent<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.content, 1024usize)
.map_err(|error| error.in_field("content"))?;
crate::validate::Validate::validate(&self.format)
.map_err(|error| error.in_field("format"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MessageContent<
CustomDataType = crate::NoCustomData,
const MESSAGE_CONTENT_CONTENT_CAP: usize = 1024usize,
> {
/// *(2.1)* Required. Message contents. +
/// Maximum length supported by Charging Station is given in OCPPCommCtrlr.FieldLength\["MessageContentType.content"\].
/// Maximum length defaults to 1024.
pub content: heapless::String<MESSAGE_CONTENT_CONTENT_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub format: MessageFormatEnum,
/// Message language identifier. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language: Option<heapless::String<8usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const MESSAGE_CONTENT_CONTENT_CAP: usize> crate::validate::Validate
for MessageContent<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.content, 1024usize)
.map_err(|error| error.in_field("content"))?;
crate::validate::Validate::validate(&self.format)
.map_err(|error| error.in_field("format"))?;
Ok(())
}
}
/// Current status of the ID Token.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AuthorizationStatusEnum {
Accepted,
Blocked,
ConcurrentTx,
Expired,
Invalid,
NoCredit,
NotAllowedTypeEVSE,
NotAtThisLocation,
NotAtThisTime,
Unknown,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for AuthorizationStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Contains status information about an identifier.
/// It is advised to not stop charging for a token that expires during charging, as ExpiryDate is only used for caching purposes. If ExpiryDate is not given, the status has no end date.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IdTokenInfo<CustomDataType = crate::NoCustomData> {
/// Date and Time after which the token must be considered invalid.
#[cfg_attr(feature = "serde", serde(rename = "cacheExpiryDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cache_expiry_date_time: Option<crate::OcppTimestamp>,
/// Priority from a business point of view. Default priority is 0, The range is from -9 to 9. Higher values indicate a higher priority. The chargingPriority in <<transactioneventresponse,TransactionEventResponse>> overrules this one.
#[cfg_attr(feature = "serde", serde(rename = "chargingPriority"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_priority: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Only used when the IdToken is only valid for one or more specific EVSEs, not for the entire Charging Station.
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_id: Option<alloc::vec::Vec<i64>>,
#[cfg_attr(feature = "serde", serde(rename = "groupIdToken"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub group_id_token: Option<IdToken<CustomDataType>>,
/// Preferred user interface language of identifier user. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language1: Option<heapless::String<8usize>>,
/// Second preferred user interface language of identifier user. Don’t use when language1 is omitted, has to be different from language1. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language2: Option<heapless::String<8usize>>,
#[cfg_attr(feature = "serde", serde(rename = "personalMessage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub personal_message: Option<MessageContent<CustomDataType>>,
pub status: AuthorizationStatusEnum,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for IdTokenInfo<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.evse_id {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evseId"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::check_min_i64(*item, 0i64)
.map_err(|error| error.in_index(index).in_field("evseId"))?;
}
}
if let Some(value) = &self.group_id_token {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("groupIdToken"))?;
}
if let Some(value) = &self.personal_message {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("personalMessage"))?;
}
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Contains status information about an identifier.
/// It is advised to not stop charging for a token that expires during charging, as ExpiryDate is only used for caching purposes. If ExpiryDate is not given, the status has no end date.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IdTokenInfo<
CustomDataType = crate::NoCustomData,
const ID_TOKEN_INFO_EVSE_ID_CAP: usize = 8usize,
const ID_TOKEN_ADDITIONAL_INFO_CAP: usize = 8usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize = 1024usize,
> {
/// Date and Time after which the token must be considered invalid.
#[cfg_attr(feature = "serde", serde(rename = "cacheExpiryDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cache_expiry_date_time: Option<crate::OcppTimestamp>,
/// Priority from a business point of view. Default priority is 0, The range is from -9 to 9. Higher values indicate a higher priority. The chargingPriority in <<transactioneventresponse,TransactionEventResponse>> overrules this one.
#[cfg_attr(feature = "serde", serde(rename = "chargingPriority"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_priority: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Only used when the IdToken is only valid for one or more specific EVSEs, not for the entire Charging Station.
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_id: Option<heapless::Vec<i64, ID_TOKEN_INFO_EVSE_ID_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "groupIdToken"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub group_id_token: Option<IdToken<CustomDataType, ID_TOKEN_ADDITIONAL_INFO_CAP>>,
/// Preferred user interface language of identifier user. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language1: Option<heapless::String<8usize>>,
/// Second preferred user interface language of identifier user. Don’t use when language1 is omitted, has to be different from language1. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub language2: Option<heapless::String<8usize>>,
#[cfg_attr(feature = "serde", serde(rename = "personalMessage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub personal_message: Option<
MessageContent<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP>,
>,
pub status: AuthorizationStatusEnum,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const ID_TOKEN_INFO_EVSE_ID_CAP: usize,
const ID_TOKEN_ADDITIONAL_INFO_CAP: usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize,
> crate::validate::Validate
for IdTokenInfo<
CustomDataType,
ID_TOKEN_INFO_EVSE_ID_CAP,
ID_TOKEN_ADDITIONAL_INFO_CAP,
MESSAGE_CONTENT_CONTENT_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.evse_id {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evseId"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::check_min_i64(*item, 0i64)
.map_err(|error| error.in_index(index).in_field("evseId"))?;
}
}
if let Some(value) = &self.group_id_token {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("groupIdToken"))?;
}
if let Some(value) = &self.personal_message {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("personalMessage"))?;
}
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DayOfWeekEnum {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DayOfWeekEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of EVSE (AC, DC) this tariff applies to.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EvseKindEnum {
AC,
DC,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for EvseKindEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// These conditions describe if and when a TariffEnergyType or TariffTimeType applies during a transaction.
///
/// When more than one restriction is set, they are to be treated as a logical AND. All need to be valid before this price is active.
///
/// For reverse energy flow (discharging) negative values of energy, power and current are used.
///
/// NOTE: _minXXX_ (where XXX = Kwh/A/Kw) must be read as "closest to zero", and _maxXXX_ as "furthest from zero". For example, a *charging* power range from 10 kW to 50 kWh is given by _minPower_ = 10000 and _maxPower_ = 50000, and a *discharging* power range from -10 kW to -50 kW is given by _minPower_ = -10 and _maxPower_ = -50.
///
/// NOTE: _startTimeOfDay_ and _endTimeOfDay_ are in local time, because it is the time in the tariff as it is shown to the EV driver at the Charging Station.
/// A Charging Station will convert this to the internal time zone that it uses (which is recommended to be UTC, see section Generic chapter 3.1) when performing cost calculation.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffConditions<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Day(s) of the week this is tariff applies.
#[cfg_attr(feature = "serde", serde(rename = "dayOfWeek"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub day_of_week: Option<heapless::Vec<DayOfWeekEnum, 7usize>>,
/// End time of day in local time. Same syntax as _startTimeOfDay_. +
/// If end time < start time then the period wraps around to the next day. +
/// To stop at end of the day use: 00:00.
#[cfg_attr(feature = "serde", serde(rename = "endTimeOfDay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub end_time_of_day: Option<crate::OcppTimeOfDay>,
#[cfg_attr(feature = "serde", serde(rename = "evseKind"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_kind: Option<EvseKindEnum>,
/// Maximum duration in seconds the charging MUST last (exclusive).
/// When the duration of a charging is shorter than the defined value, this price is or becomes active.
/// After that moment, this price is no longer active.
#[cfg_attr(feature = "serde", serde(rename = "maxChargingTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charging_time: Option<i64>,
/// Sum of the maximum current (in Amperes) over all phases, for example 20 A.
/// When the EV is charging with less than the defined amount of current, this price becomes/is active. If the charging current is or becomes higher, this price is not or no longer valid and becomes inactive.
/// This is NOT about the maximum current over the entire transaction.
#[cfg_attr(feature = "serde", serde(rename = "maxCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_current: Option<f64>,
/// Maximum consumed energy in Wh, for example 50000 Wh.
/// Valid until this amount of energy (exclusive) being used.
#[cfg_attr(feature = "serde", serde(rename = "maxEnergy"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_energy: Option<f64>,
/// Maximum duration in seconds the idle period (i.e. not charging) MUST last (exclusive).
/// When the duration of idle time is shorter than the defined value, this price is or becomes active.
/// After that moment, this price is no longer active.
#[cfg_attr(feature = "serde", serde(rename = "maxIdleTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_idle_time: Option<i64>,
/// Maximum power in W, for example 20000 W.
/// When the EV is charging with less than the defined amount of power, this price becomes/is active.
/// If the charging power is or becomes higher, this price is not or no longer valid and becomes inactive.
/// This is NOT about the maximum power over the entire transaction.
#[cfg_attr(feature = "serde", serde(rename = "maxPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_power: Option<f64>,
/// Maximum duration in seconds the transaction (charging & idle) MUST last (exclusive).
/// When the duration of a transaction is shorter than the defined value, this price is or becomes active.
/// After that moment, this price is no longer active.
#[cfg_attr(feature = "serde", serde(rename = "maxTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_time: Option<i64>,
/// Minimum duration in seconds the charging MUST last (inclusive).
/// When the duration of a charging is longer than the defined value, this price is or becomes active.
/// Before that moment, this price is not yet active.
#[cfg_attr(feature = "serde", serde(rename = "minChargingTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charging_time: Option<i64>,
/// Sum of the minimum current (in Amperes) over all phases, for example 5 A.
/// When the EV is charging with more than, or equal to, the defined amount of current, this price is/becomes active. If the charging current is or becomes lower, this price is not or no longer valid and becomes inactive. +
/// This is NOT about the minimum current over the entire transaction.
#[cfg_attr(feature = "serde", serde(rename = "minCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_current: Option<f64>,
/// Minimum consumed energy in Wh, for example 20000 Wh.
/// Valid from this amount of energy (inclusive) being used.
#[cfg_attr(feature = "serde", serde(rename = "minEnergy"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_energy: Option<f64>,
/// Minimum duration in seconds the idle period (i.e. not charging) MUST last (inclusive).
/// When the duration of the idle time is longer than the defined value, this price is or becomes active.
/// Before that moment, this price is not yet active.
#[cfg_attr(feature = "serde", serde(rename = "minIdleTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_idle_time: Option<i64>,
/// Minimum power in W, for example 5000 W.
/// When the EV is charging with more than, or equal to, the defined amount of power, this price is/becomes active.
/// If the charging power is or becomes lower, this price is not or no longer valid and becomes inactive.
/// This is NOT about the minimum power over the entire transaction.
#[cfg_attr(feature = "serde", serde(rename = "minPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_power: Option<f64>,
/// Minimum duration in seconds the transaction (charging & idle) MUST last (inclusive).
/// When the duration of a transaction is longer than the defined value, this price is or becomes active.
/// Before that moment, this price is not yet active.
#[cfg_attr(feature = "serde", serde(rename = "minTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_time: Option<i64>,
/// Start time of day in local time. +
/// Format as per RFC 3339: time-hour ":" time-minute +
/// Must be in 24h format with leading zeros. Hour/Minute separator: ":"
/// Regex: (\[0-1\]\[0-9\]\|2\[0-3\]):\[0-5\]\[0-9\]
#[cfg_attr(feature = "serde", serde(rename = "startTimeOfDay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time_of_day: Option<crate::OcppTimeOfDay>,
/// Start date in local time, for example: 2015-12-24.
/// Valid from this day (inclusive). +
/// Format as per RFC 3339: full-date +
///
/// Regex: (\[12\]\[0-9\]{3})-(0\[1-9\]\|1\[0-2\])-(0\[1-9\]\|\[12\]\[0-9\]\|3\[01\])
#[cfg_attr(feature = "serde", serde(rename = "validFromDate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from_date: Option<crate::OcppDate>,
/// End date in local time, for example: 2015-12-27.
/// Valid until this day (exclusive). Same syntax as _validFromDate_.
#[cfg_attr(feature = "serde", serde(rename = "validToDate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_to_date: Option<crate::OcppDate>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TariffConditions<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.day_of_week {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("dayOfWeek"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("dayOfWeek"))?;
}
}
if let Some(value) = &self.evse_kind {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evseKind"))?;
}
Ok(())
}
}
/// Tariff with optional conditions for a time duration price.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffTimePrice<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub conditions: Option<TariffConditions<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Price per minute (excl. tax) for this element.
#[cfg_attr(feature = "serde", serde(rename = "priceMinute"))]
pub price_minute: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TariffTimePrice<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.conditions {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("conditions"))?;
}
Ok(())
}
}
/// Tax percentage
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TaxRate<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Stack level for this type of tax. Default value, when absent, is 0. +
/// _stack_ = 0: tax on net price; +
/// _stack_ = 1: tax added on top of _stack_ 0; +
/// _stack_ = 2: tax added on top of _stack_ 1, etc.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub stack: Option<i64>,
/// Tax percentage
pub tax: f64,
/// Type of this tax, e.g. "Federal ", "State", for information on receipt.
pub r#type: heapless::String<20usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TaxRate<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.stack {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("stack"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Price elements and tax for time
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffTime<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: alloc::vec::Vec<TariffTimePrice<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for TariffTime<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Price elements and tax for time
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffTime<
CustomDataType = crate::NoCustomData,
const TARIFF_TIME_PRICES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: heapless::Vec<TariffTimePrice<CustomDataType>, TARIFF_TIME_PRICES_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const TARIFF_TIME_PRICES_CAP: usize> crate::validate::Validate
for TariffTime<CustomDataType, TARIFF_TIME_PRICES_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
/// Tariff with optional conditions for an energy price.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffEnergyPrice<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub conditions: Option<TariffConditions<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Price per kWh (excl. tax) for this element.
#[cfg_attr(feature = "serde", serde(rename = "priceKwh"))]
pub price_kwh: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TariffEnergyPrice<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.conditions {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("conditions"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Price elements and tax for energy
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffEnergy<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: alloc::vec::Vec<TariffEnergyPrice<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for TariffEnergy<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Price elements and tax for energy
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffEnergy<
CustomDataType = crate::NoCustomData,
const TARIFF_ENERGY_PRICES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: heapless::Vec<
TariffEnergyPrice<CustomDataType>,
TARIFF_ENERGY_PRICES_CAP,
>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const TARIFF_ENERGY_PRICES_CAP: usize> crate::validate::Validate
for TariffEnergy<CustomDataType, TARIFF_ENERGY_PRICES_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
/// These conditions describe if a FixedPrice applies at start of the transaction.
///
/// When more than one restriction is set, they are to be treated as a logical AND. All need to be valid before this price is active.
///
/// NOTE: _startTimeOfDay_ and _endTimeOfDay_ are in local time, because it is the time in the tariff as it is shown to the EV driver at the Charging Station.
/// A Charging Station will convert this to the internal time zone that it uses (which is recommended to be UTC, see section Generic chapter 3.1) when performing cost calculation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffConditionsFixed<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Day(s) of the week this is tariff applies.
#[cfg_attr(feature = "serde", serde(rename = "dayOfWeek"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub day_of_week: Option<heapless::Vec<DayOfWeekEnum, 7usize>>,
/// End time of day in local time. Same syntax as _startTimeOfDay_. +
/// If end time < start time then the period wraps around to the next day. +
/// To stop at end of the day use: 00:00.
#[cfg_attr(feature = "serde", serde(rename = "endTimeOfDay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub end_time_of_day: Option<crate::OcppTimeOfDay>,
#[cfg_attr(feature = "serde", serde(rename = "evseKind"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_kind: Option<EvseKindEnum>,
/// For which payment brand this (adhoc) tariff applies. Can be used to add a surcharge for certain payment brands.
/// Based on value of _additionalIdToken_ from _idToken.additionalInfo.type_ = "PaymentBrand".
#[cfg_attr(feature = "serde", serde(rename = "paymentBrand"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub payment_brand: Option<heapless::String<20usize>>,
/// Type of adhoc payment, e.g. CC, Debit.
/// Based on value of _additionalIdToken_ from _idToken.additionalInfo.type_ = "PaymentRecognition".
#[cfg_attr(feature = "serde", serde(rename = "paymentRecognition"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub payment_recognition: Option<heapless::String<20usize>>,
/// Start time of day in local time. +
/// Format as per RFC 3339: time-hour ":" time-minute +
/// Must be in 24h format with leading zeros. Hour/Minute separator: ":"
/// Regex: (\[0-1\]\[0-9\]\|2\[0-3\]):\[0-5\]\[0-9\]
#[cfg_attr(feature = "serde", serde(rename = "startTimeOfDay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time_of_day: Option<crate::OcppTimeOfDay>,
/// Start date in local time, for example: 2015-12-24.
/// Valid from this day (inclusive). +
/// Format as per RFC 3339: full-date +
///
/// Regex: (\[12\]\[0-9\]{3})-(0\[1-9\]\|1\[0-2\])-(0\[1-9\]\|\[12\]\[0-9\]\|3\[01\])
#[cfg_attr(feature = "serde", serde(rename = "validFromDate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from_date: Option<crate::OcppDate>,
/// End date in local time, for example: 2015-12-27.
/// Valid until this day (exclusive). Same syntax as _validFromDate_.
#[cfg_attr(feature = "serde", serde(rename = "validToDate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_to_date: Option<crate::OcppDate>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for TariffConditionsFixed<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.day_of_week {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("dayOfWeek"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("dayOfWeek"))?;
}
}
if let Some(value) = &self.evse_kind {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evseKind"))?;
}
Ok(())
}
}
/// Tariff with optional conditions for a fixed price.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffFixedPrice<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub conditions: Option<TariffConditionsFixed<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Fixed price for this element e.g. a start fee.
#[cfg_attr(feature = "serde", serde(rename = "priceFixed"))]
pub price_fixed: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TariffFixedPrice<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.conditions {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("conditions"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffFixed<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: alloc::vec::Vec<TariffFixedPrice<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for TariffFixed<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffFixed<
CustomDataType = crate::NoCustomData,
const TARIFF_FIXED_PRICES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub prices: heapless::Vec<TariffFixedPrice<CustomDataType>, TARIFF_FIXED_PRICES_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const TARIFF_FIXED_PRICES_CAP: usize> crate::validate::Validate
for TariffFixed<CustomDataType, TARIFF_FIXED_PRICES_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.prices.len(), 1usize)
.map_err(|error| error.in_field("prices"))?;
for (index, item) in self.prices.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("prices"))?;
}
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
/// Price with and without tax. At least one of _exclTax_, _inclTax_ must be present.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Price<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Price/cost excluding tax. Can be absent if _inclTax_ is present.
#[cfg_attr(feature = "serde", serde(rename = "exclTax"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub excl_tax: Option<f64>,
/// Price/cost including tax. Can be absent if _exclTax_ is present.
#[cfg_attr(feature = "serde", serde(rename = "inclTax"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub incl_tax: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "taxRates"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rates: Option<heapless::Vec<TaxRate<CustomDataType>, 5usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Price<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.tax_rates {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRates"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRates"))?;
}
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// A tariff is described by fields with prices for:
/// energy,
/// charging time,
/// idle time,
/// fixed fee,
/// reservation time,
/// reservation fixed fee. +
/// Each of these fields may have (optional) conditions that specify when a price is applicable. +
/// The _description_ contains a human-readable explanation of the tariff to be shown to the user. +
/// The other fields are parameters that define the tariff. These are used by the charging station to calculate the price.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Tariff<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_time: Option<TariffTime<CustomDataType>>,
/// Currency code according to ISO 4217
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub description: Option<heapless::Vec<MessageContent<CustomDataType>, 10usize>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub energy: Option<TariffEnergy<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "fixedFee"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub fixed_fee: Option<TariffFixed<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "idleTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub idle_time: Option<TariffTime<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "maxCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_cost: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "minCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_cost: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationFixed"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_fixed: Option<TariffFixed<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_time: Option<TariffTime<CustomDataType>>,
/// Unique id of tariff
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
pub tariff_id: heapless::String<60usize>,
/// Time when this tariff becomes active. When absent, it is immediately active.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for Tariff<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingTime"))?;
}
if let Some(value) = &self.description {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("description"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("description"))?;
}
}
if let Some(value) = &self.energy {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("energy"))?;
}
if let Some(value) = &self.fixed_fee {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("fixedFee"))?;
}
if let Some(value) = &self.idle_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("idleTime"))?;
}
if let Some(value) = &self.max_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("maxCost"))?;
}
if let Some(value) = &self.min_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("minCost"))?;
}
if let Some(value) = &self.reservation_fixed {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationFixed"))?;
}
if let Some(value) = &self.reservation_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationTime"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// A tariff is described by fields with prices for:
/// energy,
/// charging time,
/// idle time,
/// fixed fee,
/// reservation time,
/// reservation fixed fee. +
/// Each of these fields may have (optional) conditions that specify when a price is applicable. +
/// The _description_ contains a human-readable explanation of the tariff to be shown to the user. +
/// The other fields are parameters that define the tariff. These are used by the charging station to calculate the price.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Tariff<
CustomDataType = crate::NoCustomData,
const TARIFF_TIME_PRICES_CAP: usize = 8usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize = 1024usize,
const TARIFF_ENERGY_PRICES_CAP: usize = 8usize,
const TARIFF_FIXED_PRICES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "chargingTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_time: Option<TariffTime<CustomDataType, TARIFF_TIME_PRICES_CAP>>,
/// Currency code according to ISO 4217
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub description: Option<
heapless::Vec<
MessageContent<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP>,
10usize,
>,
>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub energy: Option<TariffEnergy<CustomDataType, TARIFF_ENERGY_PRICES_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "fixedFee"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub fixed_fee: Option<TariffFixed<CustomDataType, TARIFF_FIXED_PRICES_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "idleTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub idle_time: Option<TariffTime<CustomDataType, TARIFF_TIME_PRICES_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "maxCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_cost: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "minCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_cost: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationFixed"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_fixed: Option<TariffFixed<CustomDataType, TARIFF_FIXED_PRICES_CAP>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_time: Option<TariffTime<CustomDataType, TARIFF_TIME_PRICES_CAP>>,
/// Unique id of tariff
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
pub tariff_id: heapless::String<60usize>,
/// Time when this tariff becomes active. When absent, it is immediately active.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const TARIFF_TIME_PRICES_CAP: usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize,
const TARIFF_ENERGY_PRICES_CAP: usize,
const TARIFF_FIXED_PRICES_CAP: usize,
> crate::validate::Validate
for Tariff<
CustomDataType,
TARIFF_TIME_PRICES_CAP,
MESSAGE_CONTENT_CONTENT_CAP,
TARIFF_ENERGY_PRICES_CAP,
TARIFF_FIXED_PRICES_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingTime"))?;
}
if let Some(value) = &self.description {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("description"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("description"))?;
}
}
if let Some(value) = &self.energy {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("energy"))?;
}
if let Some(value) = &self.fixed_fee {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("fixedFee"))?;
}
if let Some(value) = &self.idle_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("idleTime"))?;
}
if let Some(value) = &self.max_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("maxCost"))?;
}
if let Some(value) = &self.min_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("minCost"))?;
}
if let Some(value) = &self.reservation_fixed {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationFixed"))?;
}
if let Some(value) = &self.reservation_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationTime"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BatteryData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Slot number where battery is inserted or removed.
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
pub evse_id: i64,
/// Production date of battery.
#[cfg_attr(feature = "serde", serde(rename = "productionDate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub production_date: Option<crate::OcppTimestamp>,
/// Serial number of battery.
#[cfg_attr(feature = "serde", serde(rename = "serialNumber"))]
pub serial_number: heapless::String<50usize>,
/// State of charge
#[cfg_attr(feature = "serde", serde(rename = "soC"))]
pub so_c: f64,
/// State of health
#[cfg_attr(feature = "serde", serde(rename = "soH"))]
pub so_h: f64,
/// Vendor-specific info from battery in undefined format.
#[cfg_attr(feature = "serde", serde(rename = "vendorInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub vendor_info: Option<heapless::String<500usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for BatteryData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.evse_id, 0i64)
.map_err(|error| error.in_field("evseId"))?;
crate::validate::check_min_f64(self.so_c, 0f64)
.map_err(|error| error.in_field("soC"))?;
crate::validate::check_max_f64(self.so_c, 100f64)
.map_err(|error| error.in_field("soC"))?;
crate::validate::check_min_f64(self.so_h, 0f64)
.map_err(|error| error.in_field("soH"))?;
crate::validate::check_max_f64(self.so_h, 100f64)
.map_err(|error| error.in_field("soH"))?;
Ok(())
}
}
/// Battery in/out
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BatterySwapEventEnum {
BatteryIn,
BatteryOut,
BatteryOutTimeout,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for BatterySwapEventEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Defines parameters required for initiating and maintaining wireless communication with other devices.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Modem<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// This contains the ICCID of the modem’s SIM card.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub iccid: Option<heapless::String<20usize>>,
/// This contains the IMSI of the modem’s SIM card.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub imsi: Option<heapless::String<20usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Modem<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// The physical system where an Electrical Vehicle (EV) can be charged.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingStation<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// This contains the firmware version of the Charging Station.
#[cfg_attr(feature = "serde", serde(rename = "firmwareVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub firmware_version: Option<heapless::String<50usize>>,
/// Defines the model of the device.
pub model: heapless::String<20usize>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub modem: Option<Modem<CustomDataType>>,
/// Vendor-specific device identifier.
#[cfg_attr(feature = "serde", serde(rename = "serialNumber"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub serial_number: Option<heapless::String<25usize>>,
/// Identifies the vendor (not necessarily in a unique manner).
#[cfg_attr(feature = "serde", serde(rename = "vendorName"))]
pub vendor_name: heapless::String<50usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ChargingStation<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.modem {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("modem"))?;
}
Ok(())
}
}
/// This contains the reason for sending this message to the CSMS.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BootReasonEnum {
ApplicationReset,
FirmwareUpdate,
LocalReset,
PowerUp,
RemoteReset,
ScheduledReset,
Triggered,
Unknown,
Watchdog,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for BootReasonEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains whether the Charging Station has been registered
/// within the CSMS.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RegistrationStatusEnum {
Accepted,
Pending,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for RegistrationStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates the success or failure of the canceling of a reservation by CSMS.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CancelReservationStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CancelReservationStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates the type of the signed certificate that is returned. When omitted the certificate is used for both the 15118 connection (if implemented) and the Charging Station to CSMS connection. This field is required when a typeOfCertificate was included in the <<signcertificaterequest,SignCertificateRequest>> that requested this certificate to be signed AND both the 15118 connection and the Charging Station connection are implemented.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CertificateSigningUseEnum {
ChargingStationCertificate,
V2GCertificate,
V2G20Certificate,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CertificateSigningUseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Returns whether certificate signing has been accepted, otherwise rejected.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CertificateSignedStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CertificateSignedStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Electric Vehicle Supply Equipment
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVSE<CustomDataType = crate::NoCustomData> {
/// An id to designate a specific connector (on an EVSE) by connector index number.
#[cfg_attr(feature = "serde", serde(rename = "connectorId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub connector_id: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// EVSE Identifier. This contains a number (> 0) designating an EVSE of the Charging Station.
pub id: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for EVSE<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.connector_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("connectorId"))?;
}
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
Ok(())
}
}
/// This contains the type of availability change that the Charging Station should perform.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OperationalStatusEnum {
Inoperative,
Operative,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for OperationalStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station is able to perform the availability change.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChangeAvailabilityStatusEnum {
Accepted,
Rejected,
Scheduled,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChangeAvailabilityStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Status of the operation
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffChangeStatusEnum {
Accepted,
Rejected,
TooManyElements,
ConditionNotSupported,
TxNotFound,
NoCurrencyChange,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffChangeStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Accepted if the Charging Station has executed the request, otherwise rejected.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClearCacheStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ClearCacheStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Specifies to purpose of the charging profiles that will be cleared, if they meet the other criteria in the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChargingProfilePurposeEnum {
ChargingStationExternalConstraints,
ChargingStationMaxProfile,
TxDefaultProfile,
TxProfile,
PriorityCharging,
LocalGeneration,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChargingProfilePurposeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// A ClearChargingProfileType is a filter for charging profiles to be cleared by ClearChargingProfileRequest.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClearChargingProfile<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingProfilePurpose"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_profile_purpose: Option<ChargingProfilePurposeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Specifies the id of the EVSE for which to clear charging profiles. An evseId of zero (0) specifies the charging profile for the overall Charging Station. Absence of this parameter means the clearing applies to all charging profiles that match the other criteria in the request.
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_id: Option<i64>,
/// Specifies the stackLevel for which charging profiles will be cleared, if they meet the other criteria in the request.
#[cfg_attr(feature = "serde", serde(rename = "stackLevel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub stack_level: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ClearChargingProfile<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_profile_purpose {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingProfilePurpose"))?;
}
if let Some(value) = self.evse_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("evseId"))?;
}
if let Some(value) = self.stack_level {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("stackLevel"))?;
}
Ok(())
}
}
/// Indicates if the Charging Station was able to execute the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClearChargingProfileStatusEnum {
Accepted,
Unknown,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ClearChargingProfileStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Name of control settings to clear. Not used when _controlId_ is provided.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DERControlEnum {
EnterService,
FreqDroop,
FreqWatt,
FixedPFAbsorb,
FixedPFInject,
FixedVar,
Gradients,
HFMustTrip,
HFMayTrip,
HVMustTrip,
HVMomCess,
HVMayTrip,
LimitMaxDischarge,
LFMustTrip,
LVMustTrip,
LVMomCess,
LVMayTrip,
PowerMonitoringMustTrip,
VoltVar,
VoltWatt,
WattPF,
WattVar,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DERControlEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Result of operation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DERControlStatusEnum {
Accepted,
Rejected,
NotSupported,
NotFound,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DERControlStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Returns whether the Charging Station has been able to remove the message.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClearMessageStatusEnum {
Accepted,
Unknown,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ClearMessageStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffClearStatusEnum {
Accepted,
Rejected,
NoTariff,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffClearStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClearTariffsResult<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub status: TariffClearStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType>>,
/// Id of tariff for which _status_ is reported. If no tariffs were found, then this field is absent, and _status_ will be `NoTariff`.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tariff_id: Option<heapless::String<60usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ClearTariffsResult<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClearTariffsResult<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub status: TariffClearStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP>>,
/// Id of tariff for which _status_ is reported. If no tariffs were found, then this field is absent, and _status_ will be `NoTariff`.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tariff_id: Option<heapless::String<60usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
> crate::validate::Validate
for ClearTariffsResult<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
Ok(())
}
}
/// Result of the clear request for this monitor, identified by its Id.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClearMonitoringStatusEnum {
Accepted,
Rejected,
NotFound,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ClearMonitoringStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClearMonitoringResult<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id of the monitor of which a clear was requested.
pub id: i64,
pub status: ClearMonitoringStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for ClearMonitoringResult<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClearMonitoringResult<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id of the monitor of which a clear was requested.
pub id: i64,
pub status: ClearMonitoringStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
> crate::validate::Validate
for ClearMonitoringResult<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CertificateHashData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "hashAlgorithm"))]
pub hash_algorithm: HashAlgorithmEnum,
/// The hash of the DER encoded public key:
/// the value (excluding tag and length) of the subject
/// public key field in the issuer’s certificate.
#[cfg_attr(feature = "serde", serde(rename = "issuerKeyHash"))]
pub issuer_key_hash: heapless::String<128usize>,
/// The hash of the issuer’s distinguished
/// name (DN), that must be calculated over the DER
/// encoding of the issuer’s name field in the certificate
/// being checked.
#[cfg_attr(feature = "serde", serde(rename = "issuerNameHash"))]
pub issuer_name_hash: heapless::String<128usize>,
/// The string representation of the
/// hexadecimal value of the serial number without the
/// prefix "0x" and without leading zeroes.
#[cfg_attr(feature = "serde", serde(rename = "serialNumber"))]
pub serial_number: heapless::String<40usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for CertificateHashData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.hash_algorithm)
.map_err(|error| error.in_field("hashAlgorithm"))?;
Ok(())
}
}
/// Indicates whether the request was accepted.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CustomerInformationStatusEnum {
Accepted,
Rejected,
Invalid,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CustomerInformationStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates the success or failure of the data transfer.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DataTransferStatusEnum {
Accepted,
Rejected,
UnknownMessageId,
UnknownVendorId,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DataTransferStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Charging Station indicates if it can process the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DeleteCertificateStatusEnum {
Accepted,
Failed,
NotFound,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DeleteCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains the progress status of the firmware installation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FirmwareStatusEnum {
Downloaded,
DownloadFailed,
Downloading,
DownloadScheduled,
DownloadPaused,
Idle,
InstallationFailed,
Installing,
Installed,
InstallRebooting,
InstallScheduled,
InstallVerificationFailed,
InvalidSignature,
SignatureVerified,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for FirmwareStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Defines whether certificate needs to be installed or updated.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CertificateActionEnum {
Install,
Update,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CertificateActionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates whether the message was processed properly.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Iso15118EVCertificateStatusEnum {
Accepted,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for Iso15118EVCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This field specifies the report base.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReportBaseEnum {
ConfigurationInventory,
FullInventory,
SummaryInventory,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ReportBaseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station is able to accept this request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GenericDeviceModelStatusEnum {
Accepted,
Rejected,
NotSupported,
EmptyResultSet,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GenericDeviceModelStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Source of status: OCSP, CRL
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CertificateStatusSourceEnum {
CRL,
OCSP,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CertificateStatusSourceEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Data necessary to request the revocation status of a certificate.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CertificateStatusRequestInfo<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "certificateHashData"))]
pub certificate_hash_data: CertificateHashData<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub source: CertificateStatusSourceEnum,
/// URL(s) of _source_.
pub urls: heapless::Vec<alloc::string::String, 5usize>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for CertificateStatusRequestInfo<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.certificate_hash_data)
.map_err(|error| error.in_field("certificateHashData"))?;
crate::validate::Validate::validate(&self.source)
.map_err(|error| error.in_field("source"))?;
crate::validate::check_min_items(self.urls.len(), 1usize)
.map_err(|error| error.in_field("urls"))?;
for (index, item) in self.urls.iter().enumerate() {
crate::validate::check_max_length(item, 2000usize)
.map_err(|error| error.in_index(index).in_field("urls"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Data necessary to request the revocation status of a certificate.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CertificateStatusRequestInfo<
CustomDataType = crate::NoCustomData,
const CERTIFICATE_STATUS_REQUEST_INFO_URLS_ITEM_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "certificateHashData"))]
pub certificate_hash_data: CertificateHashData<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub source: CertificateStatusSourceEnum,
/// URL(s) of _source_.
pub urls: heapless::Vec<
heapless::String<CERTIFICATE_STATUS_REQUEST_INFO_URLS_ITEM_CAP>,
5usize,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const CERTIFICATE_STATUS_REQUEST_INFO_URLS_ITEM_CAP: usize,
> crate::validate::Validate
for CertificateStatusRequestInfo<
CustomDataType,
CERTIFICATE_STATUS_REQUEST_INFO_URLS_ITEM_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.certificate_hash_data)
.map_err(|error| error.in_field("certificateHashData"))?;
crate::validate::Validate::validate(&self.source)
.map_err(|error| error.in_field("source"))?;
crate::validate::check_min_items(self.urls.len(), 1usize)
.map_err(|error| error.in_field("urls"))?;
for (index, item) in self.urls.iter().enumerate() {
crate::validate::check_max_length(item, 2000usize)
.map_err(|error| error.in_index(index).in_field("urls"))?;
}
Ok(())
}
}
/// Status of certificate: good, revoked or unknown.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CertificateStatusEnum {
Good,
Revoked,
Unknown,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Revocation status of certificate
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CertificateStatus<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "certificateHashData"))]
pub certificate_hash_data: CertificateHashData<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "nextUpdate"))]
pub next_update: crate::OcppTimestamp,
pub source: CertificateStatusSourceEnum,
pub status: CertificateStatusEnum,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for CertificateStatus<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.certificate_hash_data)
.map_err(|error| error.in_field("certificateHashData"))?;
crate::validate::Validate::validate(&self.source)
.map_err(|error| error.in_field("source"))?;
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
Ok(())
}
}
/// This indicates whether the charging station was able to retrieve the OCSP certificate status.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetCertificateStatusEnum {
Accepted,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// A ChargingProfileCriterionType is a filter for charging profiles to be selected by a GetChargingProfilesRequest.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingProfileCriterion<CustomDataType = crate::NoCustomData> {
/// For which charging limit sources, charging profiles SHALL be reported. If omitted, the Charging Station SHALL not filter on chargingLimitSource. Values defined in Appendix as ChargingLimitSourceEnumStringType.
#[cfg_attr(feature = "serde", serde(rename = "chargingLimitSource"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_limit_source: Option<heapless::Vec<heapless::String<20usize>, 4usize>>,
/// List of all the chargingProfileIds requested. Any ChargingProfile that matches one of these profiles will be reported. If omitted, the Charging Station SHALL not filter on chargingProfileId. This field SHALL NOT contain more ids than set in <<configkey-charging-profile-entries,ChargingProfileEntries.maxLimit>>
#[cfg_attr(feature = "serde", serde(rename = "chargingProfileId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_profile_id: Option<alloc::vec::Vec<i64>>,
#[cfg_attr(feature = "serde", serde(rename = "chargingProfilePurpose"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_profile_purpose: Option<ChargingProfilePurposeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[cfg_attr(feature = "serde", serde(rename = "stackLevel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub stack_level: Option<i64>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for ChargingProfileCriterion<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_limit_source {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingLimitSource"))?;
}
if let Some(value) = &self.charging_profile_id {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingProfileId"))?;
}
if let Some(value) = &self.charging_profile_purpose {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingProfilePurpose"))?;
}
if let Some(value) = self.stack_level {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("stackLevel"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// A ChargingProfileCriterionType is a filter for charging profiles to be selected by a GetChargingProfilesRequest.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingProfileCriterion<
CustomDataType = crate::NoCustomData,
const CHARGING_PROFILE_CRITERION_CHARGING_PROFILE_ID_CAP: usize = 8usize,
> {
/// For which charging limit sources, charging profiles SHALL be reported. If omitted, the Charging Station SHALL not filter on chargingLimitSource. Values defined in Appendix as ChargingLimitSourceEnumStringType.
#[cfg_attr(feature = "serde", serde(rename = "chargingLimitSource"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_limit_source: Option<heapless::Vec<heapless::String<20usize>, 4usize>>,
/// List of all the chargingProfileIds requested. Any ChargingProfile that matches one of these profiles will be reported. If omitted, the Charging Station SHALL not filter on chargingProfileId. This field SHALL NOT contain more ids than set in <<configkey-charging-profile-entries,ChargingProfileEntries.maxLimit>>
#[cfg_attr(feature = "serde", serde(rename = "chargingProfileId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_profile_id: Option<
heapless::Vec<i64, CHARGING_PROFILE_CRITERION_CHARGING_PROFILE_ID_CAP>,
>,
#[cfg_attr(feature = "serde", serde(rename = "chargingProfilePurpose"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_profile_purpose: Option<ChargingProfilePurposeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[cfg_attr(feature = "serde", serde(rename = "stackLevel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub stack_level: Option<i64>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const CHARGING_PROFILE_CRITERION_CHARGING_PROFILE_ID_CAP: usize,
> crate::validate::Validate
for ChargingProfileCriterion<
CustomDataType,
CHARGING_PROFILE_CRITERION_CHARGING_PROFILE_ID_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_limit_source {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingLimitSource"))?;
}
if let Some(value) = &self.charging_profile_id {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingProfileId"))?;
}
if let Some(value) = &self.charging_profile_purpose {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingProfilePurpose"))?;
}
if let Some(value) = self.stack_level {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("stackLevel"))?;
}
Ok(())
}
}
/// This indicates whether the Charging Station is able to process this request and will send <<reportchargingprofilesrequest, ReportChargingProfilesRequest>> messages.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetChargingProfileStatusEnum {
Accepted,
NoProfiles,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetChargingProfileStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Can be used to force a power or current profile.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChargingRateUnitEnum {
W,
A,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChargingRateUnitEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* Charging operation mode to use during this time interval. When absent defaults to `ChargingOnly`.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OperationModeEnum {
Idle,
ChargingOnly,
CentralSetpoint,
ExternalSetpoint,
ExternalLimits,
CentralFrequency,
LocalFrequency,
LocalLoadBalancing,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for OperationModeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* A point of a frequency-watt curve.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct V2XFreqWattPoint<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Net frequency in Hz.
pub frequency: f64,
/// Power in W to charge (positive) or discharge (negative) at specified frequency.
pub power: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for V2XFreqWattPoint<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* A point of a signal-watt curve.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct V2XSignalWattPoint<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Power in W to charge (positive) or discharge (negative) at specified frequency.
pub power: f64,
/// Signal value from an AFRRSignalRequest.
pub signal: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for V2XSignalWattPoint<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Charging schedule period structure defines a time period in a charging schedule. It is used in: CompositeScheduleType and in ChargingScheduleType. When used in a NotifyEVChargingScheduleRequest only _startPeriod_, _limit_, _limit_L2_, _limit_L3_ are relevant.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingSchedulePeriod<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Limit in _chargingRateUnit_ that the EV is allowed to discharge with. Note, these are negative values in order to be consistent with _setpoint_, which can be positive and negative. +
/// For AC this field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L2 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l2: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L3 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l3: Option<f64>,
/// *(2.1)* If true, the EVSE must turn off power electronics/modules associated with this transaction. Default value when absent is false.
#[cfg_attr(feature = "serde", serde(rename = "evseSleep"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_sleep: Option<bool>,
/// Optional only when not required by the _operationMode_, as in CentralSetpoint, ExternalSetpoint, ExternalLimits, LocalFrequency, LocalLoadBalancing. +
/// Charging rate limit during the schedule period, in the applicable _chargingRateUnit_.
/// This SHOULD be a non-negative value; a negative value is only supported for backwards compatibility with older systems that use a negative value to specify a discharging limit.
/// When using _chargingRateUnit_ = `W`, this field represents the sum of the power of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit: Option<f64>,
/// *(2.1)* Charging rate limit on phase L2 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l2: Option<f64>,
/// *(2.1)* Charging rate limit on phase L3 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l3: Option<f64>,
/// The number of phases that can be used for charging. +
/// For a DC EVSE this field should be omitted. +
/// For an AC EVSE a default value of _numberPhases_ = 3 will be assumed if the field is absent.
#[cfg_attr(feature = "serde", serde(rename = "numberPhases"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub number_phases: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "operationMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub operation_mode: Option<OperationModeEnum>,
/// Values: 1..3, Used if numberPhases=1 and if the EVSE is capable of switching the phase connected to the EV, i.e. ACPhaseSwitchingSupported is defined and true. It’s not allowed unless both conditions above are true. If both conditions are true, and phaseToUse is omitted, the Charging Station / EVSE will make the selection on its own.
#[cfg_attr(feature = "serde", serde(rename = "phaseToUse"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub phase_to_use: Option<i64>,
/// *(2.1)* If true, the EV should attempt to keep the BMS preconditioned for this time interval.
#[cfg_attr(feature = "serde", serde(rename = "preconditioningRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub preconditioning_request: Option<bool>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow as close as possible. Use negative values for discharging. +
/// When a limit and/or _dischargeLimit_ are given the overshoot when following _setpoint_ must remain within these values.
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow as closely as possible. Positive values for inductive, negative for capacitive reactive power or current. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L2 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l2: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L3 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l3: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L2 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l2: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L3 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l3: Option<f64>,
/// Start of the period, in seconds from the start of schedule. The value of StartPeriod also defines the stop time of the previous period.
#[cfg_attr(feature = "serde", serde(rename = "startPeriod"))]
pub start_period: i64,
/// *(2.1)* Power value that, when present, is used as a baseline on top of which values from _v2xFreqWattCurve_ and _v2xSignalWattCurve_ are added.
#[cfg_attr(feature = "serde", serde(rename = "v2xBaseline"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_baseline: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "v2xFreqWattCurve"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_freq_watt_curve: Option<alloc::vec::Vec<V2XFreqWattPoint<CustomDataType>>>,
#[cfg_attr(feature = "serde", serde(rename = "v2xSignalWattCurve"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_signal_watt_curve: Option<
alloc::vec::Vec<V2XSignalWattPoint<CustomDataType>>,
>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for ChargingSchedulePeriod<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.discharge_limit {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit"))?;
}
if let Some(value) = self.discharge_limit_l2 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L2"))?;
}
if let Some(value) = self.discharge_limit_l3 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L3"))?;
}
if let Some(value) = self.number_phases {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("numberPhases"))?;
crate::validate::check_max_i64(value, 3i64)
.map_err(|error| error.in_field("numberPhases"))?;
}
if let Some(value) = &self.operation_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("operationMode"))?;
}
if let Some(value) = self.phase_to_use {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("phaseToUse"))?;
crate::validate::check_max_i64(value, 3i64)
.map_err(|error| error.in_field("phaseToUse"))?;
}
if let Some(value) = &self.v2x_freq_watt_curve {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("v2xFreqWattCurve"))?;
crate::validate::check_max_items(value.len(), 20usize)
.map_err(|error| error.in_field("v2xFreqWattCurve"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("v2xFreqWattCurve")
})?;
}
}
if let Some(value) = &self.v2x_signal_watt_curve {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("v2xSignalWattCurve"))?;
crate::validate::check_max_items(value.len(), 20usize)
.map_err(|error| error.in_field("v2xSignalWattCurve"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("v2xSignalWattCurve")
})?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Charging schedule period structure defines a time period in a charging schedule. It is used in: CompositeScheduleType and in ChargingScheduleType. When used in a NotifyEVChargingScheduleRequest only _startPeriod_, _limit_, _limit_L2_, _limit_L3_ are relevant.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingSchedulePeriod<
CustomDataType = crate::NoCustomData,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Limit in _chargingRateUnit_ that the EV is allowed to discharge with. Note, these are negative values in order to be consistent with _setpoint_, which can be positive and negative. +
/// For AC this field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L2 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l2: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L3 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l3: Option<f64>,
/// *(2.1)* If true, the EVSE must turn off power electronics/modules associated with this transaction. Default value when absent is false.
#[cfg_attr(feature = "serde", serde(rename = "evseSleep"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_sleep: Option<bool>,
/// Optional only when not required by the _operationMode_, as in CentralSetpoint, ExternalSetpoint, ExternalLimits, LocalFrequency, LocalLoadBalancing. +
/// Charging rate limit during the schedule period, in the applicable _chargingRateUnit_.
/// This SHOULD be a non-negative value; a negative value is only supported for backwards compatibility with older systems that use a negative value to specify a discharging limit.
/// When using _chargingRateUnit_ = `W`, this field represents the sum of the power of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit: Option<f64>,
/// *(2.1)* Charging rate limit on phase L2 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l2: Option<f64>,
/// *(2.1)* Charging rate limit on phase L3 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l3: Option<f64>,
/// The number of phases that can be used for charging. +
/// For a DC EVSE this field should be omitted. +
/// For an AC EVSE a default value of _numberPhases_ = 3 will be assumed if the field is absent.
#[cfg_attr(feature = "serde", serde(rename = "numberPhases"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub number_phases: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "operationMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub operation_mode: Option<OperationModeEnum>,
/// Values: 1..3, Used if numberPhases=1 and if the EVSE is capable of switching the phase connected to the EV, i.e. ACPhaseSwitchingSupported is defined and true. It’s not allowed unless both conditions above are true. If both conditions are true, and phaseToUse is omitted, the Charging Station / EVSE will make the selection on its own.
#[cfg_attr(feature = "serde", serde(rename = "phaseToUse"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub phase_to_use: Option<i64>,
/// *(2.1)* If true, the EV should attempt to keep the BMS preconditioned for this time interval.
#[cfg_attr(feature = "serde", serde(rename = "preconditioningRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub preconditioning_request: Option<bool>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow as close as possible. Use negative values for discharging. +
/// When a limit and/or _dischargeLimit_ are given the overshoot when following _setpoint_ must remain within these values.
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow as closely as possible. Positive values for inductive, negative for capacitive reactive power or current. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L2 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l2: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L3 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l3: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L2 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l2: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L3 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l3: Option<f64>,
/// Start of the period, in seconds from the start of schedule. The value of StartPeriod also defines the stop time of the previous period.
#[cfg_attr(feature = "serde", serde(rename = "startPeriod"))]
pub start_period: i64,
/// *(2.1)* Power value that, when present, is used as a baseline on top of which values from _v2xFreqWattCurve_ and _v2xSignalWattCurve_ are added.
#[cfg_attr(feature = "serde", serde(rename = "v2xBaseline"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_baseline: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "v2xFreqWattCurve"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_freq_watt_curve: Option<
heapless::Vec<
V2XFreqWattPoint<CustomDataType>,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "v2xSignalWattCurve"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_signal_watt_curve: Option<
heapless::Vec<
V2XSignalWattPoint<CustomDataType>,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
>,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize,
> crate::validate::Validate
for ChargingSchedulePeriod<
CustomDataType,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.discharge_limit {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit"))?;
}
if let Some(value) = self.discharge_limit_l2 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L2"))?;
}
if let Some(value) = self.discharge_limit_l3 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L3"))?;
}
if let Some(value) = self.number_phases {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("numberPhases"))?;
crate::validate::check_max_i64(value, 3i64)
.map_err(|error| error.in_field("numberPhases"))?;
}
if let Some(value) = &self.operation_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("operationMode"))?;
}
if let Some(value) = self.phase_to_use {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("phaseToUse"))?;
crate::validate::check_max_i64(value, 3i64)
.map_err(|error| error.in_field("phaseToUse"))?;
}
if let Some(value) = &self.v2x_freq_watt_curve {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("v2xFreqWattCurve"))?;
crate::validate::check_max_items(value.len(), 20usize)
.map_err(|error| error.in_field("v2xFreqWattCurve"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("v2xFreqWattCurve")
})?;
}
}
if let Some(value) = &self.v2x_signal_watt_curve {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("v2xSignalWattCurve"))?;
crate::validate::check_max_items(value.len(), 20usize)
.map_err(|error| error.in_field("v2xSignalWattCurve"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("v2xSignalWattCurve")
})?;
}
}
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CompositeSchedule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingRateUnit"))]
pub charging_rate_unit: ChargingRateUnitEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedulePeriod"))]
pub charging_schedule_period: alloc::vec::Vec<
ChargingSchedulePeriod<CustomDataType>,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub duration: i64,
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
pub evse_id: i64,
#[cfg_attr(feature = "serde", serde(rename = "scheduleStart"))]
pub schedule_start: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for CompositeSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.charging_rate_unit)
.map_err(|error| error.in_field("chargingRateUnit"))?;
crate::validate::check_min_items(self.charging_schedule_period.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
for (index, item) in self.charging_schedule_period.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("chargingSchedulePeriod")
})?;
}
crate::validate::check_min_i64(self.evse_id, 0i64)
.map_err(|error| error.in_field("evseId"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CompositeSchedule<
CustomDataType = crate::NoCustomData,
const COMPOSITE_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "chargingRateUnit"))]
pub charging_rate_unit: ChargingRateUnitEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedulePeriod"))]
pub charging_schedule_period: heapless::Vec<
ChargingSchedulePeriod<
CustomDataType,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
>,
COMPOSITE_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub duration: i64,
#[cfg_attr(feature = "serde", serde(rename = "evseId"))]
pub evse_id: i64,
#[cfg_attr(feature = "serde", serde(rename = "scheduleStart"))]
pub schedule_start: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const COMPOSITE_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize,
> crate::validate::Validate
for CompositeSchedule<
CustomDataType,
COMPOSITE_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.charging_rate_unit)
.map_err(|error| error.in_field("chargingRateUnit"))?;
crate::validate::check_min_items(self.charging_schedule_period.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
for (index, item) in self.charging_schedule_period.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("chargingSchedulePeriod")
})?;
}
crate::validate::check_min_i64(self.evse_id, 0i64)
.map_err(|error| error.in_field("evseId"))?;
Ok(())
}
}
/// If provided the Charging Station shall return Display Messages with the given priority only.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MessagePriorityEnum {
AlwaysFront,
InFront,
NormalCycle,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MessagePriorityEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// If provided the Charging Station shall return Display Messages with the given state only.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MessageStateEnum {
Charging,
Faulted,
Idle,
Unavailable,
Suspended,
Discharging,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MessageStateEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates if the Charging Station has Display Messages that match the request criteria in the <<getdisplaymessagesrequest,GetDisplayMessagesRequest>>
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetDisplayMessagesStatusEnum {
Accepted,
Unknown,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetDisplayMessagesStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetCertificateIdUseEnum {
V2GRootCertificate,
MORootCertificate,
CSMSRootCertificate,
V2GCertificateChain,
ManufacturerRootCertificate,
OEMRootCertificate,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetCertificateIdUseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CertificateHashDataChain<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "certificateHashData"))]
pub certificate_hash_data: CertificateHashData<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "certificateType"))]
pub certificate_type: GetCertificateIdUseEnum,
#[cfg_attr(feature = "serde", serde(rename = "childCertificateHashData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub child_certificate_hash_data: Option<
heapless::Vec<CertificateHashData<CustomDataType>, 4usize>,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for CertificateHashDataChain<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.certificate_hash_data)
.map_err(|error| error.in_field("certificateHashData"))?;
crate::validate::Validate::validate(&self.certificate_type)
.map_err(|error| error.in_field("certificateType"))?;
if let Some(value) = &self.child_certificate_hash_data {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("childCertificateHashData"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("childCertificateHashData")
})?;
}
}
Ok(())
}
}
/// Charging Station indicates if it can process the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetInstalledCertificateStatusEnum {
Accepted,
NotFound,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetInstalledCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Generic class for the configuration of logging entries.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LogParameters<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// This contains the date and time of the latest logging information to include in the diagnostics.
#[cfg_attr(feature = "serde", serde(rename = "latestTimestamp"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub latest_timestamp: Option<crate::OcppTimestamp>,
/// This contains the date and time of the oldest logging information to include in the diagnostics.
#[cfg_attr(feature = "serde", serde(rename = "oldestTimestamp"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub oldest_timestamp: Option<crate::OcppTimestamp>,
/// The URL of the location at the remote system where the log should be stored.
#[cfg_attr(feature = "serde", serde(rename = "remoteLocation"))]
pub remote_location: alloc::string::String,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for LogParameters<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.remote_location, 2000usize)
.map_err(|error| error.in_field("remoteLocation"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Generic class for the configuration of logging entries.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LogParameters<
CustomDataType = crate::NoCustomData,
const LOG_PARAMETERS_REMOTE_LOCATION_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// This contains the date and time of the latest logging information to include in the diagnostics.
#[cfg_attr(feature = "serde", serde(rename = "latestTimestamp"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub latest_timestamp: Option<crate::OcppTimestamp>,
/// This contains the date and time of the oldest logging information to include in the diagnostics.
#[cfg_attr(feature = "serde", serde(rename = "oldestTimestamp"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub oldest_timestamp: Option<crate::OcppTimestamp>,
/// The URL of the location at the remote system where the log should be stored.
#[cfg_attr(feature = "serde", serde(rename = "remoteLocation"))]
pub remote_location: heapless::String<LOG_PARAMETERS_REMOTE_LOCATION_CAP>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const LOG_PARAMETERS_REMOTE_LOCATION_CAP: usize,
> crate::validate::Validate
for LogParameters<CustomDataType, LOG_PARAMETERS_REMOTE_LOCATION_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.remote_location, 2000usize)
.map_err(|error| error.in_field("remoteLocation"))?;
Ok(())
}
}
/// This contains the type of log file that the Charging Station
/// should send.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LogEnum {
DiagnosticsLog,
SecurityLog,
DataCollectorLog,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for LogEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This field indicates whether the Charging Station was able to accept the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LogStatusEnum {
Accepted,
Rejected,
AcceptedCanceled,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for LogStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// A physical or logical component
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Component<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse: Option<EVSE<CustomDataType>>,
/// Name of instance in case the component exists as multiple instances. Case Insensitive. strongly advised to use Camel Case.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub instance: Option<heapless::String<50usize>>,
/// Name of the component. Name should be taken from the list of standardized component names whenever possible. Case Insensitive. strongly advised to use Camel Case.
pub name: heapless::String<50usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Component<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.evse {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evse"))?;
}
Ok(())
}
}
/// Reference key to a component-variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Variable<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Name of instance in case the variable exists as multiple instances. Case Insensitive. strongly advised to use Camel Case.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub instance: Option<heapless::String<50usize>>,
/// Name of the variable. Name should be taken from the list of standardized variable names whenever possible. Case Insensitive. strongly advised to use Camel Case.
pub name: heapless::String<50usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Variable<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Class to report components, variables and variable attributes and characteristics.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ComponentVariable<CustomDataType = crate::NoCustomData> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variable: Option<Variable<CustomDataType>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ComponentVariable<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
if let Some(value) = &self.variable {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("variable"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MonitoringCriterionEnum {
ThresholdMonitoring,
DeltaMonitoring,
PeriodicMonitoring,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MonitoringCriterionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConstantStreamData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Uniquely identifies the stream
pub id: i64,
pub params: PeriodicEventStreamParams<CustomDataType>,
/// Id of monitor used to report his event. It can be a preconfigured or hardwired monitor.
#[cfg_attr(feature = "serde", serde(rename = "variableMonitoringId"))]
pub variable_monitoring_id: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ConstantStreamData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::Validate::validate(&self.params)
.map_err(|error| error.in_field("params"))?;
crate::validate::check_min_i64(self.variable_monitoring_id, 0i64)
.map_err(|error| error.in_field("variableMonitoringId"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ComponentCriterionEnum {
Active,
Available,
Enabled,
Problem,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ComponentCriterionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Status of operation
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffGetStatusEnum {
Accepted,
Rejected,
NoTariff,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffGetStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Kind of tariff (driver/default)
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffKindEnum {
DefaultTariff,
DriverTariff,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffKindEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Shows assignment of tariffs to EVSE or IdToken.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffAssignment<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evseIds"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_ids: Option<alloc::vec::Vec<i64>>,
/// IdTokens related to tariff
#[cfg_attr(feature = "serde", serde(rename = "idTokens"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id_tokens: Option<alloc::vec::Vec<heapless::String<255usize>>>,
/// Tariff id.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
pub tariff_id: heapless::String<60usize>,
#[cfg_attr(feature = "serde", serde(rename = "tariffKind"))]
pub tariff_kind: TariffKindEnum,
/// Date/time when this tariff become active.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for TariffAssignment<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.evse_ids {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evseIds"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::check_min_i64(*item, 0i64)
.map_err(|error| error.in_index(index).in_field("evseIds"))?;
}
}
if let Some(value) = &self.id_tokens {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("idTokens"))?;
}
crate::validate::Validate::validate(&self.tariff_kind)
.map_err(|error| error.in_field("tariffKind"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Shows assignment of tariffs to EVSE or IdToken.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TariffAssignment<
CustomDataType = crate::NoCustomData,
const TARIFF_ASSIGNMENT_EVSE_IDS_CAP: usize = 8usize,
const TARIFF_ASSIGNMENT_ID_TOKENS_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evseIds"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub evse_ids: Option<heapless::Vec<i64, TARIFF_ASSIGNMENT_EVSE_IDS_CAP>>,
/// IdTokens related to tariff
#[cfg_attr(feature = "serde", serde(rename = "idTokens"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id_tokens: Option<
heapless::Vec<heapless::String<255usize>, TARIFF_ASSIGNMENT_ID_TOKENS_CAP>,
>,
/// Tariff id.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
pub tariff_id: heapless::String<60usize>,
#[cfg_attr(feature = "serde", serde(rename = "tariffKind"))]
pub tariff_kind: TariffKindEnum,
/// Date/time when this tariff become active.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const TARIFF_ASSIGNMENT_EVSE_IDS_CAP: usize,
const TARIFF_ASSIGNMENT_ID_TOKENS_CAP: usize,
> crate::validate::Validate
for TariffAssignment<
CustomDataType,
TARIFF_ASSIGNMENT_EVSE_IDS_CAP,
TARIFF_ASSIGNMENT_ID_TOKENS_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.evse_ids {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evseIds"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::check_min_i64(*item, 0i64)
.map_err(|error| error.in_index(index).in_field("evseIds"))?;
}
}
if let Some(value) = &self.id_tokens {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("idTokens"))?;
}
crate::validate::Validate::validate(&self.tariff_kind)
.map_err(|error| error.in_field("tariffKind"))?;
Ok(())
}
}
/// Attribute type for which value is requested. When absent, default Actual is assumed.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AttributeEnum {
Actual,
Target,
MinSet,
MaxSet,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for AttributeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Class to hold parameters for GetVariables request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GetVariableData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for GetVariableData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GetVariableStatusEnum {
Accepted,
Rejected,
UnknownComponent,
UnknownVariable,
NotSupportedAttributeType,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GetVariableStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Class to hold results of GetVariables request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GetVariableResult<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "attributeStatus"))]
pub attribute_status: GetVariableStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "attributeStatusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_status_info: Option<StatusInfo<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
/// Value of requested attribute type of component-variable. This field can only be empty when the given status is NOT accepted.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "attributeValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_value: Option<alloc::string::String>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for GetVariableResult<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.attribute_status)
.map_err(|error| error.in_field("attributeStatus"))?;
if let Some(value) = &self.attribute_status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeStatusInfo"))?;
}
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
if let Some(value) = &self.attribute_value {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("attributeValue"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Class to hold results of GetVariables request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GetVariableResult<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
const GET_VARIABLE_RESULT_ATTRIBUTE_VALUE_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "attributeStatus"))]
pub attribute_status: GetVariableStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "attributeStatusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_status_info: Option<
StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP>,
>,
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
/// Value of requested attribute type of component-variable. This field can only be empty when the given status is NOT accepted.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "attributeValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_value: Option<
heapless::String<GET_VARIABLE_RESULT_ATTRIBUTE_VALUE_CAP>,
>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
const GET_VARIABLE_RESULT_ATTRIBUTE_VALUE_CAP: usize,
> crate::validate::Validate
for GetVariableResult<
CustomDataType,
STATUS_INFO_ADDITIONAL_INFO_CAP,
GET_VARIABLE_RESULT_ATTRIBUTE_VALUE_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.attribute_status)
.map_err(|error| error.in_field("attributeStatus"))?;
if let Some(value) = &self.attribute_status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeStatusInfo"))?;
}
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
if let Some(value) = &self.attribute_value {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("attributeValue"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
/// Indicates the certificate type that is sent.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum InstallCertificateUseEnum {
V2GRootCertificate,
MORootCertificate,
ManufacturerRootCertificate,
CSMSRootCertificate,
OEMRootCertificate,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for InstallCertificateUseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Charging Station indicates if installation was successful.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum InstallCertificateStatusEnum {
Accepted,
Rejected,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for InstallCertificateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains the status of the log upload.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum UploadLogStatusEnum {
BadMessage,
Idle,
NotSupportedOperation,
PermissionDenied,
Uploaded,
UploadFailure,
Uploading,
AcceptedCanceled,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for UploadLogStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of detail value: start, end or sample. Default = "Sample.Periodic"
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReadingContextEnum {
#[cfg_attr(feature = "serde", serde(rename = "Interruption.Begin"))]
InterruptionBegin,
#[cfg_attr(feature = "serde", serde(rename = "Interruption.End"))]
InterruptionEnd,
Other,
#[cfg_attr(feature = "serde", serde(rename = "Sample.Clock"))]
SampleClock,
#[cfg_attr(feature = "serde", serde(rename = "Sample.Periodic"))]
SamplePeriodic,
#[cfg_attr(feature = "serde", serde(rename = "Transaction.Begin"))]
TransactionBegin,
#[cfg_attr(feature = "serde", serde(rename = "Transaction.End"))]
TransactionEnd,
Trigger,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ReadingContextEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates where the measured value has been sampled. Default = "Outlet"
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LocationEnum {
Body,
Cable,
EV,
Inlet,
Outlet,
Upstream,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for LocationEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of measurement. Default = "Energy.Active.Import.Register"
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MeasurandEnum {
#[cfg_attr(feature = "serde", serde(rename = "Current.Export"))]
CurrentExport,
#[cfg_attr(feature = "serde", serde(rename = "Current.Export.Offered"))]
CurrentExportOffered,
#[cfg_attr(feature = "serde", serde(rename = "Current.Export.Minimum"))]
CurrentExportMinimum,
#[cfg_attr(feature = "serde", serde(rename = "Current.Import"))]
CurrentImport,
#[cfg_attr(feature = "serde", serde(rename = "Current.Import.Offered"))]
CurrentImportOffered,
#[cfg_attr(feature = "serde", serde(rename = "Current.Import.Minimum"))]
CurrentImportMinimum,
#[cfg_attr(feature = "serde", serde(rename = "Current.Offered"))]
CurrentOffered,
#[cfg_attr(feature = "serde", serde(rename = "Display.PresentSOC"))]
DisplayPresentSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.MinimumSOC"))]
DisplayMinimumSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.TargetSOC"))]
DisplayTargetSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.MaximumSOC"))]
DisplayMaximumSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.RemainingTimeToMinimumSOC"))]
DisplayRemainingTimeToMinimumSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.RemainingTimeToTargetSOC"))]
DisplayRemainingTimeToTargetSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.RemainingTimeToMaximumSOC"))]
DisplayRemainingTimeToMaximumSOC,
#[cfg_attr(feature = "serde", serde(rename = "Display.ChargingComplete"))]
DisplayChargingComplete,
#[cfg_attr(feature = "serde", serde(rename = "Display.BatteryEnergyCapacity"))]
DisplayBatteryEnergyCapacity,
#[cfg_attr(feature = "serde", serde(rename = "Display.InletHot"))]
DisplayInletHot,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Export.Interval"))]
EnergyActiveExportInterval,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Export.Register"))]
EnergyActiveExportRegister,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Import.Interval"))]
EnergyActiveImportInterval,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Import.Register"))]
EnergyActiveImportRegister,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Import.CableLoss"))]
EnergyActiveImportCableLoss,
#[cfg_attr(
feature = "serde",
serde(rename = "Energy.Active.Import.LocalGeneration.Register")
)]
EnergyActiveImportLocalGenerationRegister,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Net"))]
EnergyActiveNet,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Active.Setpoint.Interval"))]
EnergyActiveSetpointInterval,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Apparent.Export"))]
EnergyApparentExport,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Apparent.Import"))]
EnergyApparentImport,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Apparent.Net"))]
EnergyApparentNet,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Reactive.Export.Interval"))]
EnergyReactiveExportInterval,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Reactive.Export.Register"))]
EnergyReactiveExportRegister,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Reactive.Import.Interval"))]
EnergyReactiveImportInterval,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Reactive.Import.Register"))]
EnergyReactiveImportRegister,
#[cfg_attr(feature = "serde", serde(rename = "Energy.Reactive.Net"))]
EnergyReactiveNet,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Target"))]
EnergyRequestTarget,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Minimum"))]
EnergyRequestMinimum,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Maximum"))]
EnergyRequestMaximum,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Minimum.V2X"))]
EnergyRequestMinimumV2X,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Maximum.V2X"))]
EnergyRequestMaximumV2X,
#[cfg_attr(feature = "serde", serde(rename = "EnergyRequest.Bulk"))]
EnergyRequestBulk,
Frequency,
#[cfg_attr(feature = "serde", serde(rename = "Power.Active.Export"))]
PowerActiveExport,
#[cfg_attr(feature = "serde", serde(rename = "Power.Active.Import"))]
PowerActiveImport,
#[cfg_attr(feature = "serde", serde(rename = "Power.Active.Setpoint"))]
PowerActiveSetpoint,
#[cfg_attr(feature = "serde", serde(rename = "Power.Active.Residual"))]
PowerActiveResidual,
#[cfg_attr(feature = "serde", serde(rename = "Power.Export.Minimum"))]
PowerExportMinimum,
#[cfg_attr(feature = "serde", serde(rename = "Power.Export.Offered"))]
PowerExportOffered,
#[cfg_attr(feature = "serde", serde(rename = "Power.Factor"))]
PowerFactor,
#[cfg_attr(feature = "serde", serde(rename = "Power.Import.Offered"))]
PowerImportOffered,
#[cfg_attr(feature = "serde", serde(rename = "Power.Import.Minimum"))]
PowerImportMinimum,
#[cfg_attr(feature = "serde", serde(rename = "Power.Offered"))]
PowerOffered,
#[cfg_attr(feature = "serde", serde(rename = "Power.Reactive.Export"))]
PowerReactiveExport,
#[cfg_attr(feature = "serde", serde(rename = "Power.Reactive.Import"))]
PowerReactiveImport,
SoC,
Voltage,
#[cfg_attr(feature = "serde", serde(rename = "Voltage.Minimum"))]
VoltageMinimum,
#[cfg_attr(feature = "serde", serde(rename = "Voltage.Maximum"))]
VoltageMaximum,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MeasurandEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates how the measured value is to be interpreted. For instance between L1 and neutral (L1-N) Please note that not all values of phase are applicable to all Measurands. When phase is absent, the measured value is interpreted as an overall value.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PhaseEnum {
L1,
L2,
L3,
N,
#[cfg_attr(feature = "serde", serde(rename = "L1-N"))]
L1N,
#[cfg_attr(feature = "serde", serde(rename = "L2-N"))]
L2N,
#[cfg_attr(feature = "serde", serde(rename = "L3-N"))]
L3N,
#[cfg_attr(feature = "serde", serde(rename = "L1-L2"))]
L1L2,
#[cfg_attr(feature = "serde", serde(rename = "L2-L3"))]
L2L3,
#[cfg_attr(feature = "serde", serde(rename = "L3-L1"))]
L3L1,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PhaseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Represent a signed version of the meter value.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SignedMeterValue<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Format used by the energy meter to encode the meter data. For example: OCMF or EDL.
#[cfg_attr(feature = "serde", serde(rename = "encodingMethod"))]
pub encoding_method: heapless::String<50usize>,
/// *(2.1)* Base64 encoded, sending depends on configuration variable _PublicKeyWithSignedMeterValue_.
#[cfg_attr(feature = "serde", serde(rename = "publicKey"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub public_key: Option<alloc::string::String>,
/// Base64 encoded, contains the signed data from the meter in the format specified in _encodingMethod_, which might contain more then just the meter value. It can contain information like timestamps, reference to a customer etc.
#[cfg_attr(feature = "serde", serde(rename = "signedMeterData"))]
pub signed_meter_data: alloc::string::String,
/// *(2.1)* Method used to create the digital signature. Optional, if already included in _signedMeterData_. Standard values for this are defined in Appendix as SigningMethodEnumStringType.
#[cfg_attr(feature = "serde", serde(rename = "signingMethod"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signing_method: Option<heapless::String<50usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SignedMeterValue<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.public_key {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("publicKey"))?;
}
crate::validate::check_max_length(&self.signed_meter_data, 32768usize)
.map_err(|error| error.in_field("signedMeterData"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Represent a signed version of the meter value.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SignedMeterValue<
CustomDataType = crate::NoCustomData,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize = 1024usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Format used by the energy meter to encode the meter data. For example: OCMF or EDL.
#[cfg_attr(feature = "serde", serde(rename = "encodingMethod"))]
pub encoding_method: heapless::String<50usize>,
/// *(2.1)* Base64 encoded, sending depends on configuration variable _PublicKeyWithSignedMeterValue_.
#[cfg_attr(feature = "serde", serde(rename = "publicKey"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub public_key: Option<heapless::String<SIGNED_METER_VALUE_PUBLIC_KEY_CAP>>,
/// Base64 encoded, contains the signed data from the meter in the format specified in _encodingMethod_, which might contain more then just the meter value. It can contain information like timestamps, reference to a customer etc.
#[cfg_attr(feature = "serde", serde(rename = "signedMeterData"))]
pub signed_meter_data: heapless::String<SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP>,
/// *(2.1)* Method used to create the digital signature. Optional, if already included in _signedMeterData_. Standard values for this are defined in Appendix as SigningMethodEnumStringType.
#[cfg_attr(feature = "serde", serde(rename = "signingMethod"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signing_method: Option<heapless::String<50usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize,
> crate::validate::Validate
for SignedMeterValue<
CustomDataType,
SIGNED_METER_VALUE_PUBLIC_KEY_CAP,
SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.public_key {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("publicKey"))?;
}
crate::validate::check_max_length(&self.signed_meter_data, 32768usize)
.map_err(|error| error.in_field("signedMeterData"))?;
Ok(())
}
}
/// Represents a UnitOfMeasure with a multiplier
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnitOfMeasure<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Multiplier, this value represents the exponent to base 10. I.e. multiplier 3 means 10 raised to the 3rd power. Default is 0. +
/// The _multiplier_ only multiplies the value of the measurand. It does not specify a conversion between units, for example, kW and W.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub multiplier: Option<i64>,
/// Unit of the value. Default = "Wh" if the (default) measurand is an "Energy" type.
/// This field SHALL use a value from the list Standardized Units of Measurements in Part 2 Appendices.
/// If an applicable unit is available in that list, otherwise a "custom" unit might be used.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unit: Option<heapless::String<20usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for UnitOfMeasure<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Single sampled value in MeterValues. Each value can be accompanied by optional fields.
///
/// To save on mobile data usage, default values of all of the optional fields are such that. The value without any additional fields will be interpreted, as a register reading of active import energy in Wh (Watt-hour) units.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SampledValue<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub context: Option<ReadingContextEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub location: Option<LocationEnum>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub measurand: Option<MeasurandEnum>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub phase: Option<PhaseEnum>,
#[cfg_attr(feature = "serde", serde(rename = "signedMeterValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signed_meter_value: Option<SignedMeterValue<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "unitOfMeasure"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unit_of_measure: Option<UnitOfMeasure<CustomDataType>>,
/// Indicates the measured value.
pub value: f64,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SampledValue<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.context {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("context"))?;
}
if let Some(value) = &self.location {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("location"))?;
}
if let Some(value) = &self.measurand {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("measurand"))?;
}
if let Some(value) = &self.phase {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("phase"))?;
}
if let Some(value) = &self.signed_meter_value {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("signedMeterValue"))?;
}
if let Some(value) = &self.unit_of_measure {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("unitOfMeasure"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Single sampled value in MeterValues. Each value can be accompanied by optional fields.
///
/// To save on mobile data usage, default values of all of the optional fields are such that. The value without any additional fields will be interpreted, as a register reading of active import energy in Wh (Watt-hour) units.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SampledValue<
CustomDataType = crate::NoCustomData,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize = 1024usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub context: Option<ReadingContextEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub location: Option<LocationEnum>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub measurand: Option<MeasurandEnum>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub phase: Option<PhaseEnum>,
#[cfg_attr(feature = "serde", serde(rename = "signedMeterValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signed_meter_value: Option<
SignedMeterValue<
CustomDataType,
SIGNED_METER_VALUE_PUBLIC_KEY_CAP,
SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "unitOfMeasure"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unit_of_measure: Option<UnitOfMeasure<CustomDataType>>,
/// Indicates the measured value.
pub value: f64,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize,
> crate::validate::Validate
for SampledValue<
CustomDataType,
SIGNED_METER_VALUE_PUBLIC_KEY_CAP,
SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.context {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("context"))?;
}
if let Some(value) = &self.location {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("location"))?;
}
if let Some(value) = &self.measurand {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("measurand"))?;
}
if let Some(value) = &self.phase {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("phase"))?;
}
if let Some(value) = &self.signed_meter_value {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("signedMeterValue"))?;
}
if let Some(value) = &self.unit_of_measure {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("unitOfMeasure"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Collection of one or more sampled values in MeterValuesRequest and TransactionEvent. All sampled values in a MeterValue are sampled at the same point in time.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MeterValue<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "sampledValue"))]
pub sampled_value: alloc::vec::Vec<SampledValue<CustomDataType>>,
/// Timestamp for measured value(s).
pub timestamp: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for MeterValue<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.sampled_value.len(), 1usize)
.map_err(|error| error.in_field("sampledValue"))?;
for (index, item) in self.sampled_value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("sampledValue"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Collection of one or more sampled values in MeterValuesRequest and TransactionEvent. All sampled values in a MeterValue are sampled at the same point in time.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MeterValue<
CustomDataType = crate::NoCustomData,
const METER_VALUE_SAMPLED_VALUE_CAP: usize = 8usize,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize = 1024usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "sampledValue"))]
pub sampled_value: heapless::Vec<
SampledValue<
CustomDataType,
SIGNED_METER_VALUE_PUBLIC_KEY_CAP,
SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP,
>,
METER_VALUE_SAMPLED_VALUE_CAP,
>,
/// Timestamp for measured value(s).
pub timestamp: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const METER_VALUE_SAMPLED_VALUE_CAP: usize,
const SIGNED_METER_VALUE_PUBLIC_KEY_CAP: usize,
const SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP: usize,
> crate::validate::Validate
for MeterValue<
CustomDataType,
METER_VALUE_SAMPLED_VALUE_CAP,
SIGNED_METER_VALUE_PUBLIC_KEY_CAP,
SIGNED_METER_VALUE_SIGNED_METER_DATA_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.sampled_value.len(), 1usize)
.map_err(|error| error.in_field("sampledValue"))?;
for (index, item) in self.sampled_value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("sampledValue"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NotifyAllowedEnergyTransferStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for NotifyAllowedEnergyTransferStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingLimit<CustomDataType = crate::NoCustomData> {
/// Represents the source of the charging limit. Values defined in appendix as ChargingLimitSourceEnumStringType.
#[cfg_attr(feature = "serde", serde(rename = "chargingLimitSource"))]
pub charging_limit_source: heapless::String<20usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Indicates whether the charging limit is critical for the grid.
#[cfg_attr(feature = "serde", serde(rename = "isGridCritical"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub is_grid_critical: Option<bool>,
/// *(2.1)* True when the reported limit concerns local generation that is providing extra capacity, instead of a limitation.
#[cfg_attr(feature = "serde", serde(rename = "isLocalGeneration"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub is_local_generation: Option<bool>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ChargingLimit<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RationalNumber<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The exponent to base 10 (dec)
pub exponent: i64,
/// Value which shall be multiplied.
pub value: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for RationalNumber<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AdditionalSelectedServices<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "serviceFee"))]
pub service_fee: RationalNumber<CustomDataType>,
/// Human readable string to identify this service.
#[cfg_attr(feature = "serde", serde(rename = "serviceName"))]
pub service_name: heapless::String<80usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for AdditionalSelectedServices<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.service_fee)
.map_err(|error| error.in_field("serviceFee"))?;
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OverstayRule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "overstayFee"))]
pub overstay_fee: RationalNumber<CustomDataType>,
/// Time till overstay will be reapplied
#[cfg_attr(feature = "serde", serde(rename = "overstayFeePeriod"))]
pub overstay_fee_period: i64,
/// Human readable string to identify the overstay rule.
#[cfg_attr(feature = "serde", serde(rename = "overstayRuleDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub overstay_rule_description: Option<heapless::String<32usize>>,
/// Time in seconds after trigger of the parent Overstay Rules for this particular fee to apply.
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
pub start_time: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for OverstayRule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.overstay_fee)
.map_err(|error| error.in_field("overstayFee"))?;
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OverstayRuleList<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "overstayPowerThreshold"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub overstay_power_threshold: Option<RationalNumber<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "overstayRule"))]
pub overstay_rule: heapless::Vec<OverstayRule<CustomDataType>, 5usize>,
/// Time till overstay is applied in seconds.
#[cfg_attr(feature = "serde", serde(rename = "overstayTimeThreshold"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub overstay_time_threshold: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for OverstayRuleList<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.overstay_power_threshold {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("overstayPowerThreshold"))?;
}
crate::validate::check_min_items(self.overstay_rule.len(), 1usize)
.map_err(|error| error.in_field("overstayRule"))?;
for (index, item) in self.overstay_rule.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("overstayRule"))?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PriceRule<CustomDataType = crate::NoCustomData> {
/// Number of grams of CO2 per kWh.
#[cfg_attr(feature = "serde", serde(rename = "carbonDioxideEmission"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub carbon_dioxide_emission: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "energyFee"))]
pub energy_fee: RationalNumber<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "parkingFee"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub parking_fee: Option<RationalNumber<CustomDataType>>,
/// The duration of the parking fee period (in seconds).
/// When the time enters into a ParkingFeePeriod, the ParkingFee will apply to the session. .
#[cfg_attr(feature = "serde", serde(rename = "parkingFeePeriod"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub parking_fee_period: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "powerRangeStart"))]
pub power_range_start: RationalNumber<CustomDataType>,
/// Percentage of the power that is created by renewable resources.
#[cfg_attr(feature = "serde", serde(rename = "renewableGenerationPercentage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub renewable_generation_percentage: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for PriceRule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.carbon_dioxide_emission {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("carbonDioxideEmission"))?;
}
crate::validate::Validate::validate(&self.energy_fee)
.map_err(|error| error.in_field("energyFee"))?;
if let Some(value) = &self.parking_fee {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("parkingFee"))?;
}
crate::validate::Validate::validate(&self.power_range_start)
.map_err(|error| error.in_field("powerRangeStart"))?;
if let Some(value) = self.renewable_generation_percentage {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("renewableGenerationPercentage"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("renewableGenerationPercentage"))?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PriceRuleStack<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration of the stack of price rules. he amount of seconds that define the duration of the given PriceRule(s).
pub duration: i64,
#[cfg_attr(feature = "serde", serde(rename = "priceRule"))]
pub price_rule: heapless::Vec<PriceRule<CustomDataType>, 8usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for PriceRuleStack<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.price_rule.len(), 1usize)
.map_err(|error| error.in_field("priceRule"))?;
for (index, item) in self.price_rule.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("priceRule"))?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TaxRule<CustomDataType = crate::NoCustomData> {
/// Indicates whether this tax applies to Energy Fees.
#[cfg_attr(feature = "serde", serde(rename = "appliesToEnergyFee"))]
pub applies_to_energy_fee: bool,
/// Indicates whether this tax applies to Minimum/Maximum Cost.
#[cfg_attr(feature = "serde", serde(rename = "appliesToMinimumMaximumCost"))]
pub applies_to_minimum_maximum_cost: bool,
/// Indicates whether this tax applies to Overstay Fees.
#[cfg_attr(feature = "serde", serde(rename = "appliesToOverstayFee"))]
pub applies_to_overstay_fee: bool,
/// Indicates whether this tax applies to Parking Fees.
#[cfg_attr(feature = "serde", serde(rename = "appliesToParkingFee"))]
pub applies_to_parking_fee: bool,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Indicates whether the tax is included in any price or not.
#[cfg_attr(feature = "serde", serde(rename = "taxIncludedInPrice"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_included_in_price: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "taxRate"))]
pub tax_rate: RationalNumber<CustomDataType>,
/// Id for the tax rule.
#[cfg_attr(feature = "serde", serde(rename = "taxRuleID"))]
pub tax_rule_i_d: i64,
/// Human readable string to identify the tax rule.
#[cfg_attr(feature = "serde", serde(rename = "taxRuleName"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rule_name: Option<heapless::String<100usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TaxRule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.tax_rate)
.map_err(|error| error.in_field("taxRate"))?;
crate::validate::check_min_i64(self.tax_rule_i_d, 0i64)
.map_err(|error| error.in_field("taxRuleID"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// The AbsolutePriceScheduleType is modeled after the same type that is defined in ISO 15118-20, such that if it is supplied by an EMSP as a signed EXI message, the conversion from EXI to JSON (in OCPP) and back to EXI (for ISO 15118-20) does not change the digest and therefore does not invalidate the signature.
///
/// image::images/AbsolutePriceSchedule-Simple.png\[\]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AbsolutePriceSchedule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "additionalSelectedServices"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_selected_services: Option<
heapless::Vec<AdditionalSelectedServices<CustomDataType>, 5usize>,
>,
/// Currency according to ISO 4217.
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// String that indicates what language is used for the human readable strings in the price schedule. Based on ISO 639.
pub language: heapless::String<8usize>,
#[cfg_attr(feature = "serde", serde(rename = "maximumCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub maximum_cost: Option<RationalNumber<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "minimumCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub minimum_cost: Option<RationalNumber<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "overstayRuleList"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub overstay_rule_list: Option<OverstayRuleList<CustomDataType>>,
/// A string in URN notation which shall uniquely identify an algorithm that defines how to compute an energy fee sum for a specific power profile based on the EnergyFee information from the PriceRule elements.
#[cfg_attr(feature = "serde", serde(rename = "priceAlgorithm"))]
pub price_algorithm: alloc::string::String,
#[cfg_attr(feature = "serde", serde(rename = "priceRuleStacks"))]
pub price_rule_stacks: alloc::vec::Vec<PriceRuleStack<CustomDataType>>,
/// Description of the price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_description: Option<heapless::String<160usize>>,
/// Unique ID of price schedule
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleID"))]
pub price_schedule_i_d: i64,
#[cfg_attr(feature = "serde", serde(rename = "taxRules"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rules: Option<heapless::Vec<TaxRule<CustomDataType>, 10usize>>,
/// Starting point of price schedule.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for AbsolutePriceSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_selected_services {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("additionalSelectedServices"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("additionalSelectedServices")
})?;
}
}
if let Some(value) = &self.maximum_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("maximumCost"))?;
}
if let Some(value) = &self.minimum_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("minimumCost"))?;
}
if let Some(value) = &self.overstay_rule_list {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("overstayRuleList"))?;
}
crate::validate::check_max_length(&self.price_algorithm, 2000usize)
.map_err(|error| error.in_field("priceAlgorithm"))?;
crate::validate::check_min_items(self.price_rule_stacks.len(), 1usize)
.map_err(|error| error.in_field("priceRuleStacks"))?;
crate::validate::check_max_items(self.price_rule_stacks.len(), 1024usize)
.map_err(|error| error.in_field("priceRuleStacks"))?;
for (index, item) in self.price_rule_stacks.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("priceRuleStacks"))?;
}
crate::validate::check_min_i64(self.price_schedule_i_d, 0i64)
.map_err(|error| error.in_field("priceScheduleID"))?;
if let Some(value) = &self.tax_rules {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRules"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRules"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// The AbsolutePriceScheduleType is modeled after the same type that is defined in ISO 15118-20, such that if it is supplied by an EMSP as a signed EXI message, the conversion from EXI to JSON (in OCPP) and back to EXI (for ISO 15118-20) does not change the digest and therefore does not invalidate the signature.
///
/// image::images/AbsolutePriceSchedule-Simple.png\[\]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AbsolutePriceSchedule<
CustomDataType = crate::NoCustomData,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "additionalSelectedServices"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub additional_selected_services: Option<
heapless::Vec<AdditionalSelectedServices<CustomDataType>, 5usize>,
>,
/// Currency according to ISO 4217.
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// String that indicates what language is used for the human readable strings in the price schedule. Based on ISO 639.
pub language: heapless::String<8usize>,
#[cfg_attr(feature = "serde", serde(rename = "maximumCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub maximum_cost: Option<RationalNumber<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "minimumCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub minimum_cost: Option<RationalNumber<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "overstayRuleList"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub overstay_rule_list: Option<OverstayRuleList<CustomDataType>>,
/// A string in URN notation which shall uniquely identify an algorithm that defines how to compute an energy fee sum for a specific power profile based on the EnergyFee information from the PriceRule elements.
#[cfg_attr(feature = "serde", serde(rename = "priceAlgorithm"))]
pub price_algorithm: heapless::String<ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "priceRuleStacks"))]
pub price_rule_stacks: heapless::Vec<
PriceRuleStack<CustomDataType>,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
>,
/// Description of the price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_description: Option<heapless::String<160usize>>,
/// Unique ID of price schedule
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleID"))]
pub price_schedule_i_d: i64,
#[cfg_attr(feature = "serde", serde(rename = "taxRules"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tax_rules: Option<heapless::Vec<TaxRule<CustomDataType>, 10usize>>,
/// Starting point of price schedule.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize,
> crate::validate::Validate
for AbsolutePriceSchedule<
CustomDataType,
ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.additional_selected_services {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("additionalSelectedServices"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("additionalSelectedServices")
})?;
}
}
if let Some(value) = &self.maximum_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("maximumCost"))?;
}
if let Some(value) = &self.minimum_cost {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("minimumCost"))?;
}
if let Some(value) = &self.overstay_rule_list {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("overstayRuleList"))?;
}
crate::validate::check_max_length(&self.price_algorithm, 2000usize)
.map_err(|error| error.in_field("priceAlgorithm"))?;
crate::validate::check_min_items(self.price_rule_stacks.len(), 1usize)
.map_err(|error| error.in_field("priceRuleStacks"))?;
crate::validate::check_max_items(self.price_rule_stacks.len(), 1024usize)
.map_err(|error| error.in_field("priceRuleStacks"))?;
for (index, item) in self.price_rule_stacks.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("priceRuleStacks"))?;
}
crate::validate::check_min_i64(self.price_schedule_i_d, 0i64)
.map_err(|error| error.in_field("priceScheduleID"))?;
if let Some(value) = &self.tax_rules {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("taxRules"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("taxRules"))?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LimitAtSoC<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Charging rate limit beyond the SoC value.
/// The unit is defined by _chargingSchedule.chargingRateUnit_.
pub limit: f64,
/// The SoC value beyond which the charging rate limit should be applied.
pub soc: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for LimitAtSoC<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.soc, 0i64)
.map_err(|error| error.in_field("soc"))?;
crate::validate::check_max_i64(self.soc, 100i64)
.map_err(|error| error.in_field("soc"))?;
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PriceLevelScheduleEntry<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The amount of seconds that define the duration of this given PriceLevelScheduleEntry.
pub duration: i64,
/// Defines the price level of this PriceLevelScheduleEntry (referring to NumberOfPriceLevels). Small values for the PriceLevel represent a cheaper PriceLevelScheduleEntry. Large values for the PriceLevel represent a more expensive PriceLevelScheduleEntry.
#[cfg_attr(feature = "serde", serde(rename = "priceLevel"))]
pub price_level: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for PriceLevelScheduleEntry<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.price_level, 0i64)
.map_err(|error| error.in_field("priceLevel"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// The PriceLevelScheduleType is modeled after the same type that is defined in ISO 15118-20, such that if it is supplied by an EMSP as a signed EXI message, the conversion from EXI to JSON (in OCPP) and back to EXI (for ISO 15118-20) does not change the digest and therefore does not invalidate the signature.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PriceLevelSchedule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Defines the overall number of distinct price level elements used across all PriceLevelSchedules.
#[cfg_attr(feature = "serde", serde(rename = "numberOfPriceLevels"))]
pub number_of_price_levels: i64,
#[cfg_attr(feature = "serde", serde(rename = "priceLevelScheduleEntries"))]
pub price_level_schedule_entries: alloc::vec::Vec<
PriceLevelScheduleEntry<CustomDataType>,
>,
/// Description of the price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_description: Option<heapless::String<32usize>>,
/// Unique ID of this price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleId"))]
pub price_schedule_id: i64,
/// Starting point of this price schedule.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for PriceLevelSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.number_of_price_levels, 0i64)
.map_err(|error| error.in_field("numberOfPriceLevels"))?;
crate::validate::check_min_items(self.price_level_schedule_entries.len(), 1usize)
.map_err(|error| error.in_field("priceLevelScheduleEntries"))?;
crate::validate::check_max_items(
self.price_level_schedule_entries.len(),
100usize,
)
.map_err(|error| error.in_field("priceLevelScheduleEntries"))?;
for (index, item) in self.price_level_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("priceLevelScheduleEntries")
})?;
}
crate::validate::check_min_i64(self.price_schedule_id, 0i64)
.map_err(|error| error.in_field("priceScheduleId"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// The PriceLevelScheduleType is modeled after the same type that is defined in ISO 15118-20, such that if it is supplied by an EMSP as a signed EXI message, the conversion from EXI to JSON (in OCPP) and back to EXI (for ISO 15118-20) does not change the digest and therefore does not invalidate the signature.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PriceLevelSchedule<
CustomDataType = crate::NoCustomData,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Defines the overall number of distinct price level elements used across all PriceLevelSchedules.
#[cfg_attr(feature = "serde", serde(rename = "numberOfPriceLevels"))]
pub number_of_price_levels: i64,
#[cfg_attr(feature = "serde", serde(rename = "priceLevelScheduleEntries"))]
pub price_level_schedule_entries: heapless::Vec<
PriceLevelScheduleEntry<CustomDataType>,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
>,
/// Description of the price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_description: Option<heapless::String<32usize>>,
/// Unique ID of this price schedule.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleId"))]
pub price_schedule_id: i64,
/// Starting point of this price schedule.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize,
> crate::validate::Validate
for PriceLevelSchedule<
CustomDataType,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.number_of_price_levels, 0i64)
.map_err(|error| error.in_field("numberOfPriceLevels"))?;
crate::validate::check_min_items(self.price_level_schedule_entries.len(), 1usize)
.map_err(|error| error.in_field("priceLevelScheduleEntries"))?;
crate::validate::check_max_items(
self.price_level_schedule_entries.len(),
100usize,
)
.map_err(|error| error.in_field("priceLevelScheduleEntries"))?;
for (index, item) in self.price_level_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("priceLevelScheduleEntries")
})?;
}
crate::validate::check_min_i64(self.price_schedule_id, 0i64)
.map_err(|error| error.in_field("priceScheduleId"))?;
Ok(())
}
}
/// The kind of cost referred to in the message element amount
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CostKindEnum {
CarbonDioxideEmission,
RelativePricePercentage,
RenewableGenerationPercentage,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CostKindEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Cost<CustomDataType = crate::NoCustomData> {
/// The estimated or actual cost per kWh
pub amount: i64,
/// Values: -3..3, The amountMultiplier defines the exponent to base 10 (dec). The final value is determined by: amount * 10 ^ amountMultiplier
#[cfg_attr(feature = "serde", serde(rename = "amountMultiplier"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub amount_multiplier: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "costKind"))]
pub cost_kind: CostKindEnum,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Cost<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.cost_kind)
.map_err(|error| error.in_field("costKind"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConsumptionCost<CustomDataType = crate::NoCustomData> {
pub cost: heapless::Vec<Cost<CustomDataType>, 3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The lowest level of consumption that defines the starting point of this consumption block. The block interval extends to the start of the next interval.
#[cfg_attr(feature = "serde", serde(rename = "startValue"))]
pub start_value: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ConsumptionCost<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.cost.len(), 1usize)
.map_err(|error| error.in_field("cost"))?;
for (index, item) in self.cost.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("cost"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RelativeTimeInterval<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration of the interval, in seconds.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<i64>,
/// Start of the interval, in seconds from NOW.
pub start: i64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for RelativeTimeInterval<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SalesTariffEntry<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "consumptionCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub consumption_cost: Option<heapless::Vec<ConsumptionCost<CustomDataType>, 3usize>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Defines the price level of this SalesTariffEntry (referring to NumEPriceLevels). Small values for the EPriceLevel represent a cheaper TariffEntry. Large values for the EPriceLevel represent a more expensive TariffEntry.
#[cfg_attr(feature = "serde", serde(rename = "ePriceLevel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub e_price_level: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "relativeTimeInterval"))]
pub relative_time_interval: RelativeTimeInterval<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for SalesTariffEntry<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.consumption_cost {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("consumptionCost"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("consumptionCost"))?;
}
}
if let Some(value) = self.e_price_level {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("ePriceLevel"))?;
}
crate::validate::Validate::validate(&self.relative_time_interval)
.map_err(|error| error.in_field("relativeTimeInterval"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// A SalesTariff provided by a Mobility Operator (EMSP) .
/// NOTE: This dataType is based on dataTypes from <<ref-ISOIEC15118-2,ISO 15118-2>>.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SalesTariff<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// SalesTariff identifier used to identify one sales tariff. An SAID remains a unique identifier for one schedule throughout a charging session.
pub id: i64,
/// Defines the overall number of distinct price levels used across all provided SalesTariff elements.
#[cfg_attr(feature = "serde", serde(rename = "numEPriceLevels"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub num_e_price_levels: Option<i64>,
/// A human readable title/short description of the sales tariff e.g. for HMI display purposes.
#[cfg_attr(feature = "serde", serde(rename = "salesTariffDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sales_tariff_description: Option<heapless::String<32usize>>,
#[cfg_attr(feature = "serde", serde(rename = "salesTariffEntry"))]
pub sales_tariff_entry: alloc::vec::Vec<SalesTariffEntry<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SalesTariff<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
if let Some(value) = self.num_e_price_levels {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("numEPriceLevels"))?;
}
crate::validate::check_min_items(self.sales_tariff_entry.len(), 1usize)
.map_err(|error| error.in_field("salesTariffEntry"))?;
crate::validate::check_max_items(self.sales_tariff_entry.len(), 1024usize)
.map_err(|error| error.in_field("salesTariffEntry"))?;
for (index, item) in self.sales_tariff_entry.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("salesTariffEntry"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// A SalesTariff provided by a Mobility Operator (EMSP) .
/// NOTE: This dataType is based on dataTypes from <<ref-ISOIEC15118-2,ISO 15118-2>>.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SalesTariff<
CustomDataType = crate::NoCustomData,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// SalesTariff identifier used to identify one sales tariff. An SAID remains a unique identifier for one schedule throughout a charging session.
pub id: i64,
/// Defines the overall number of distinct price levels used across all provided SalesTariff elements.
#[cfg_attr(feature = "serde", serde(rename = "numEPriceLevels"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub num_e_price_levels: Option<i64>,
/// A human readable title/short description of the sales tariff e.g. for HMI display purposes.
#[cfg_attr(feature = "serde", serde(rename = "salesTariffDescription"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sales_tariff_description: Option<heapless::String<32usize>>,
#[cfg_attr(feature = "serde", serde(rename = "salesTariffEntry"))]
pub sales_tariff_entry: heapless::Vec<
SalesTariffEntry<CustomDataType>,
SALES_TARIFF_SALES_TARIFF_ENTRY_CAP,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize,
> crate::validate::Validate
for SalesTariff<CustomDataType, SALES_TARIFF_SALES_TARIFF_ENTRY_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
if let Some(value) = self.num_e_price_levels {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("numEPriceLevels"))?;
}
crate::validate::check_min_items(self.sales_tariff_entry.len(), 1usize)
.map_err(|error| error.in_field("salesTariffEntry"))?;
crate::validate::check_max_items(self.sales_tariff_entry.len(), 1024usize)
.map_err(|error| error.in_field("salesTariffEntry"))?;
for (index, item) in self.sales_tariff_entry.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("salesTariffEntry"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Charging schedule structure defines a list of charging periods, as used in: NotifyEVChargingScheduleRequest and ChargingProfileType. When used in a NotifyEVChargingScheduleRequest only _duration_ and _chargingSchedulePeriod_ are relevant and _chargingRateUnit_ must be 'W'. +
/// An ISO 15118-20 session may provide either an _absolutePriceSchedule_ or a _priceLevelSchedule_. An ISO 15118-2 session can only provide a_salesTariff_ element. The field _digestValue_ is used when price schedule or sales tariff are signed.
///
/// image::images/ChargingSchedule-Simple.png\[\]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingSchedule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "absolutePriceSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub absolute_price_schedule: Option<AbsolutePriceSchedule<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "chargingRateUnit"))]
pub charging_rate_unit: ChargingRateUnitEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedulePeriod"))]
pub charging_schedule_period: alloc::vec::Vec<
ChargingSchedulePeriod<CustomDataType>,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Base64 encoded hash (SHA256 for ISO 15118-2, SHA512 for ISO 15118-20) of the EXI price schedule element. Used in signature.
#[cfg_attr(feature = "serde", serde(rename = "digestValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub digest_value: Option<heapless::String<88usize>>,
/// Duration of the charging schedule in seconds. If the duration is left empty, the last period will continue indefinitely or until end of the transaction in case startSchedule is absent.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<i64>,
pub id: i64,
#[cfg_attr(feature = "serde", serde(rename = "limitAtSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_at_so_c: Option<LimitAtSoC<CustomDataType>>,
/// Minimum charging rate supported by the EV. The unit of measure is defined by the chargingRateUnit. This parameter is intended to be used by a local smart charging algorithm to optimize the power allocation for in the case a charging process is inefficient at lower charging rates.
#[cfg_attr(feature = "serde", serde(rename = "minChargingRate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charging_rate: Option<f64>,
/// *(2.1)* Power tolerance when following EVPowerProfile.
#[cfg_attr(feature = "serde", serde(rename = "powerTolerance"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub power_tolerance: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "priceLevelSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_level_schedule: Option<PriceLevelSchedule<CustomDataType>>,
/// *(2.1)* Defaults to 0. When _randomizedDelay_ not equals zero, then the start of each <<cmn_chargingscheduleperiodtype,ChargingSchedulePeriodType>> is delayed by a randomly chosen number of seconds between 0 and _randomizedDelay_. Only allowed for TxProfile and TxDefaultProfile.
#[cfg_attr(feature = "serde", serde(rename = "randomizedDelay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub randomized_delay: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "salesTariff"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sales_tariff: Option<SalesTariff<CustomDataType>>,
/// *(2.1)* Id of this element for referencing in a signature.
#[cfg_attr(feature = "serde", serde(rename = "signatureId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signature_id: Option<i64>,
/// Starting point of an absolute schedule or recurring schedule.
#[cfg_attr(feature = "serde", serde(rename = "startSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_schedule: Option<crate::OcppTimestamp>,
/// *(2.1)* Defaults to false. When true, disregard time zone offset in dateTime fields of _ChargingScheduleType_ and use unqualified local time at Charging Station instead.
/// This allows the same `Absolute` or `Recurring` charging profile to be used in both summer and winter time.
#[cfg_attr(feature = "serde", serde(rename = "useLocalTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub use_local_time: Option<bool>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ChargingSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.absolute_price_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("absolutePriceSchedule"))?;
}
crate::validate::Validate::validate(&self.charging_rate_unit)
.map_err(|error| error.in_field("chargingRateUnit"))?;
crate::validate::check_min_items(self.charging_schedule_period.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
crate::validate::check_max_items(self.charging_schedule_period.len(), 1024usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
for (index, item) in self.charging_schedule_period.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("chargingSchedulePeriod")
})?;
}
if let Some(value) = &self.limit_at_so_c {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("limitAtSoC"))?;
}
if let Some(value) = &self.price_level_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("priceLevelSchedule"))?;
}
if let Some(value) = self.randomized_delay {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("randomizedDelay"))?;
}
if let Some(value) = &self.sales_tariff {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("salesTariff"))?;
}
if let Some(value) = self.signature_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("signatureId"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Charging schedule structure defines a list of charging periods, as used in: NotifyEVChargingScheduleRequest and ChargingProfileType. When used in a NotifyEVChargingScheduleRequest only _duration_ and _chargingSchedulePeriod_ are relevant and _chargingRateUnit_ must be 'W'. +
/// An ISO 15118-20 session may provide either an _absolutePriceSchedule_ or a _priceLevelSchedule_. An ISO 15118-2 session can only provide a_salesTariff_ element. The field _digestValue_ is used when price schedule or sales tariff are signed.
///
/// image::images/ChargingSchedule-Simple.png\[\]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingSchedule<
CustomDataType = crate::NoCustomData,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize = 8usize,
const CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize = 8usize,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize = 8usize,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "absolutePriceSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub absolute_price_schedule: Option<
AbsolutePriceSchedule<
CustomDataType,
ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "chargingRateUnit"))]
pub charging_rate_unit: ChargingRateUnitEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedulePeriod"))]
pub charging_schedule_period: heapless::Vec<
ChargingSchedulePeriod<
CustomDataType,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
>,
CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Base64 encoded hash (SHA256 for ISO 15118-2, SHA512 for ISO 15118-20) of the EXI price schedule element. Used in signature.
#[cfg_attr(feature = "serde", serde(rename = "digestValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub digest_value: Option<heapless::String<88usize>>,
/// Duration of the charging schedule in seconds. If the duration is left empty, the last period will continue indefinitely or until end of the transaction in case startSchedule is absent.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<i64>,
pub id: i64,
#[cfg_attr(feature = "serde", serde(rename = "limitAtSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_at_so_c: Option<LimitAtSoC<CustomDataType>>,
/// Minimum charging rate supported by the EV. The unit of measure is defined by the chargingRateUnit. This parameter is intended to be used by a local smart charging algorithm to optimize the power allocation for in the case a charging process is inefficient at lower charging rates.
#[cfg_attr(feature = "serde", serde(rename = "minChargingRate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charging_rate: Option<f64>,
/// *(2.1)* Power tolerance when following EVPowerProfile.
#[cfg_attr(feature = "serde", serde(rename = "powerTolerance"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub power_tolerance: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "priceLevelSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_level_schedule: Option<
PriceLevelSchedule<
CustomDataType,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
>,
>,
/// *(2.1)* Defaults to 0. When _randomizedDelay_ not equals zero, then the start of each <<cmn_chargingscheduleperiodtype,ChargingSchedulePeriodType>> is delayed by a randomly chosen number of seconds between 0 and _randomizedDelay_. Only allowed for TxProfile and TxDefaultProfile.
#[cfg_attr(feature = "serde", serde(rename = "randomizedDelay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub randomized_delay: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "salesTariff"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sales_tariff: Option<
SalesTariff<CustomDataType, SALES_TARIFF_SALES_TARIFF_ENTRY_CAP>,
>,
/// *(2.1)* Id of this element for referencing in a signature.
#[cfg_attr(feature = "serde", serde(rename = "signatureId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signature_id: Option<i64>,
/// Starting point of an absolute schedule or recurring schedule.
#[cfg_attr(feature = "serde", serde(rename = "startSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_schedule: Option<crate::OcppTimestamp>,
/// *(2.1)* Defaults to false. When true, disregard time zone offset in dateTime fields of _ChargingScheduleType_ and use unqualified local time at Charging Station instead.
/// This allows the same `Absolute` or `Recurring` charging profile to be used in both summer and winter time.
#[cfg_attr(feature = "serde", serde(rename = "useLocalTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub use_local_time: Option<bool>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize,
const CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize,
> crate::validate::Validate
for ChargingSchedule<
CustomDataType,
ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
SALES_TARIFF_SALES_TARIFF_ENTRY_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.absolute_price_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("absolutePriceSchedule"))?;
}
crate::validate::Validate::validate(&self.charging_rate_unit)
.map_err(|error| error.in_field("chargingRateUnit"))?;
crate::validate::check_min_items(self.charging_schedule_period.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
crate::validate::check_max_items(self.charging_schedule_period.len(), 1024usize)
.map_err(|error| error.in_field("chargingSchedulePeriod"))?;
for (index, item) in self.charging_schedule_period.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("chargingSchedulePeriod")
})?;
}
if let Some(value) = &self.limit_at_so_c {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("limitAtSoC"))?;
}
if let Some(value) = &self.price_level_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("priceLevelSchedule"))?;
}
if let Some(value) = self.randomized_delay {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("randomizedDelay"))?;
}
if let Some(value) = &self.sales_tariff {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("salesTariff"))?;
}
if let Some(value) = self.signature_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("signatureId"))?;
}
Ok(())
}
}
/// Type of grid event that caused this
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GridEventFaultEnum {
CurrentImbalance,
LocalEmergency,
LowInputPower,
OverCurrent,
OverFrequency,
OverVoltage,
PhaseRotation,
RemoteEmergency,
UnderFrequency,
UnderVoltage,
VoltageImbalance,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for GridEventFaultEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MessageInfo<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub display: Option<Component<CustomDataType>>,
/// Until what date-time should this message be shown, after this date/time this message SHALL be removed.
#[cfg_attr(feature = "serde", serde(rename = "endDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub end_date_time: Option<crate::OcppTimestamp>,
/// Unique id within an exchange context. It is defined within the OCPP context as a positive Integer value (greater or equal to zero).
pub id: i64,
pub message: MessageContent<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "messageExtra"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub message_extra: Option<heapless::Vec<MessageContent<CustomDataType>, 4usize>>,
pub priority: MessagePriorityEnum,
/// From what date-time should this message be shown. If omitted: directly.
#[cfg_attr(feature = "serde", serde(rename = "startDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_date_time: Option<crate::OcppTimestamp>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub state: Option<MessageStateEnum>,
/// During which transaction shall this message be shown.
/// Message SHALL be removed by the Charging Station after transaction has
/// ended.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for MessageInfo<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.display {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("display"))?;
}
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::Validate::validate(&self.message)
.map_err(|error| error.in_field("message"))?;
if let Some(value) = &self.message_extra {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("messageExtra"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("messageExtra"))?;
}
}
crate::validate::Validate::validate(&self.priority)
.map_err(|error| error.in_field("priority"))?;
if let Some(value) = &self.state {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("state"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MessageInfo<
CustomDataType = crate::NoCustomData,
const MESSAGE_CONTENT_CONTENT_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub display: Option<Component<CustomDataType>>,
/// Until what date-time should this message be shown, after this date/time this message SHALL be removed.
#[cfg_attr(feature = "serde", serde(rename = "endDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub end_date_time: Option<crate::OcppTimestamp>,
/// Unique id within an exchange context. It is defined within the OCPP context as a positive Integer value (greater or equal to zero).
pub id: i64,
pub message: MessageContent<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "messageExtra"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub message_extra: Option<
heapless::Vec<
MessageContent<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP>,
4usize,
>,
>,
pub priority: MessagePriorityEnum,
/// From what date-time should this message be shown. If omitted: directly.
#[cfg_attr(feature = "serde", serde(rename = "startDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_date_time: Option<crate::OcppTimestamp>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub state: Option<MessageStateEnum>,
/// During which transaction shall this message be shown.
/// Message SHALL be removed by the Charging Station after transaction has
/// ended.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const MESSAGE_CONTENT_CONTENT_CAP: usize> crate::validate::Validate
for MessageInfo<CustomDataType, MESSAGE_CONTENT_CONTENT_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.display {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("display"))?;
}
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::Validate::validate(&self.message)
.map_err(|error| error.in_field("message"))?;
if let Some(value) = &self.message_extra {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("messageExtra"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("messageExtra"))?;
}
}
crate::validate::Validate::validate(&self.priority)
.map_err(|error| error.in_field("priority"))?;
if let Some(value) = &self.state {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("state"))?;
}
Ok(())
}
}
/// EV AC charging parameters for ISO 15118-2
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ACChargingParameters<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Amount of energy requested (in Wh). This includes energy required for preconditioning.
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EAmount +
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVTargetEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "energyAmount"))]
pub energy_amount: f64,
/// Maximum current (amps) supported by the electric vehicle (per phase). Includes cable capacity.
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMaxCurrent
#[cfg_attr(feature = "serde", serde(rename = "evMaxCurrent"))]
pub ev_max_current: f64,
/// Maximum voltage supported by the electric vehicle.
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMaxVoltage
#[cfg_attr(feature = "serde", serde(rename = "evMaxVoltage"))]
pub ev_max_voltage: f64,
/// Minimum current (amps) supported by the electric vehicle (per phase).
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMinCurrent
#[cfg_attr(feature = "serde", serde(rename = "evMinCurrent"))]
pub ev_min_current: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ACChargingParameters<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* Indicates whether EV wants to operate in Dynamic or Scheduled mode. When absent, Scheduled mode is assumed for backwards compatibility. +
/// *ISO 15118-20:* +
/// ServiceSelectionReq(SelectedEnergyTransferService)
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ControlModeEnum {
ScheduledControl,
DynamicControl,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ControlModeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// EV DC charging parameters for ISO 15118-2
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DCChargingParameters<CustomDataType = crate::NoCustomData> {
/// Percentage of SoC at which the EV considers a fast charging process to end. (possible values: 0 - 100)
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: BulkSOC
#[cfg_attr(feature = "serde", serde(rename = "bulkSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub bulk_so_c: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Amount of energy requested (in Wh). This inludes energy required for preconditioning.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "energyAmount"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub energy_amount: Option<f64>,
/// Capacity of the electric vehicle battery (in Wh).
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVEnergyCapacity
#[cfg_attr(feature = "serde", serde(rename = "evEnergyCapacity"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_energy_capacity: Option<f64>,
/// Maximum current (in A) supported by the electric vehicle. Includes cable capacity.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType:EVMaximumCurrentLimit
#[cfg_attr(feature = "serde", serde(rename = "evMaxCurrent"))]
pub ev_max_current: f64,
/// Maximum power (in W) supported by the electric vehicle. Required for DC charging.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVMaximumPowerLimit
#[cfg_attr(feature = "serde", serde(rename = "evMaxPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_max_power: Option<f64>,
/// Maximum voltage supported by the electric vehicle.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVMaximumVoltageLimit
#[cfg_attr(feature = "serde", serde(rename = "evMaxVoltage"))]
pub ev_max_voltage: f64,
/// Percentage of SoC at which the EV considers the battery fully charged. (possible values: 0 - 100)
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: FullSOC
#[cfg_attr(feature = "serde", serde(rename = "fullSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub full_so_c: Option<i64>,
/// Energy available in the battery (in percent of the battery capacity)
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: DC_EVStatus: EVRESSSOC
#[cfg_attr(feature = "serde", serde(rename = "stateOfCharge"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub state_of_charge: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for DCChargingParameters<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.bulk_so_c {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("bulkSoC"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("bulkSoC"))?;
}
if let Some(value) = self.full_so_c {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("fullSoC"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("fullSoC"))?;
}
if let Some(value) = self.state_of_charge {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("stateOfCharge"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("stateOfCharge"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum IslandingDetectionEnum {
NoAntiIslandingSupport,
RoCoF,
#[cfg_attr(feature = "serde", serde(rename = "UVP_OVP"))]
UVPOVP,
#[cfg_attr(feature = "serde", serde(rename = "UFP_OFP"))]
UFPOFP,
VoltageVectorShift,
ZeroCrossingDetection,
OtherPassive,
ImpedanceMeasurement,
ImpedanceAtFrequency,
SlipModeFrequencyShift,
SandiaFrequencyShift,
SandiaVoltageShift,
FrequencyJump,
RCLQFactor,
OtherActive,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for IslandingDetectionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// *(2.1)* DERChargingParametersType is used in ChargingNeedsType during an ISO 15118-20 session for AC_BPT_DER to report the inverter settings related to DER control that were agreed between EVSE and EV.
///
/// Fields starting with "ev" contain values from the EV.
/// Other fields contain a value that is supported by both EV and EVSE.
///
/// DERChargingParametersType type is only relevant in case of an ISO 15118-20 AC_BPT_DER/AC_DER charging session.
///
/// NOTE: All these fields have values greater or equal to zero (i.e. are non-negative)
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DERChargingParameters<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Maximum allowed duration of DC injection at level 1 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel1DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evDurationLevel1DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_duration_level1_d_c_injection: Option<f64>,
/// Maximum allowed duration of DC injection at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel2DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evDurationLevel2DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_duration_level2_d_c_injection: Option<f64>,
/// Hardware version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterHwVersion
#[cfg_attr(feature = "serde", serde(rename = "evInverterHwVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_hw_version: Option<heapless::String<50usize>>,
/// Manufacturer of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterManufacturer
#[cfg_attr(feature = "serde", serde(rename = "evInverterManufacturer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_manufacturer: Option<heapless::String<50usize>>,
/// Model name of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterModel
#[cfg_attr(feature = "serde", serde(rename = "evInverterModel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_model: Option<heapless::String<50usize>>,
/// Serial number of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSerialNumber
#[cfg_attr(feature = "serde", serde(rename = "evInverterSerialNumber"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_serial_number: Option<heapless::String<50usize>>,
/// Software version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSwVersion
#[cfg_attr(feature = "serde", serde(rename = "evInverterSwVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_sw_version: Option<heapless::String<50usize>>,
/// Type of islanding detection method. Only mandatory when islanding detection is required at the site, as set in the ISO 15118 Service Details configuration. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVIslandingDetectionMethod
#[cfg_attr(feature = "serde", serde(rename = "evIslandingDetectionMethod"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_islanding_detection_method: Option<alloc::vec::Vec<IslandingDetectionEnum>>,
/// Time after which EV will trip if an island has been detected. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVIslandingTripTime
#[cfg_attr(feature = "serde", serde(rename = "evIslandingTripTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_islanding_trip_time: Option<f64>,
/// Maximum injected DC current allowed at level 1 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumLevel1DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evMaximumLevel1DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_maximum_level1_d_c_injection: Option<f64>,
/// Maximum injected DC current allowed at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumLevel2DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evMaximumLevel2DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_maximum_level2_d_c_injection: Option<f64>,
/// Rated maximum injected active power by EV, at specified over-excited power factor (overExcitedPowerFactor). +
/// It can also be defined as the rated maximum discharge power at the rated minimum injected reactive power value. This means that if the EV is providing reactive power support, and it is requested to discharge at max power (e.g. to satisfy an EMS request), the EV may override the request and discharge up to overExcitedMaximumDischargePower to meet the minimum reactive power requirements. +
/// Corresponds to the WOvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVOverExcitedMaximumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "evOverExcitedMaxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_over_excited_max_discharge_power: Option<f64>,
/// EV power factor when injecting (over excited) the minimum reactive power. +
/// Corresponds to the OvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVOverExcitedPowerFactor
#[cfg_attr(feature = "serde", serde(rename = "evOverExcitedPowerFactor"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_over_excited_power_factor: Option<f64>,
/// Measure of the susceptibility of the circuit to reactance, in Siemens (S). +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVReactiveSusceptance
#[cfg_attr(feature = "serde", serde(rename = "evReactiveSusceptance"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_reactive_susceptance: Option<f64>,
/// Total energy value, in Wh, that EV is allowed to provide during the entire V2G session. The value is independent of the V2X Cycling area. Once this value reaches the value of 0, the EV may block any attempt to discharge in order to protect the battery health.
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVSessionTotalDischargeEnergyAvailable
#[cfg_attr(
feature = "serde",
serde(rename = "evSessionTotalDischargeEnergyAvailable")
)]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_session_total_discharge_energy_available: Option<f64>,
/// DER control functions supported by EV. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType:DERControlFunctions (bitmap)
#[cfg_attr(feature = "serde", serde(rename = "evSupportedDERControl"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_supported_d_e_r_control: Option<alloc::vec::Vec<DERControlEnum>>,
/// Rated maximum injected active power by EV supported at specified under-excited power factor (EVUnderExcitedPowerFactor). +
/// It can also be defined as the rated maximum dischargePower at the rated minimum absorbed reactive power value.
/// This means that if the EV is providing reactive power support, and it is requested to discharge at max power (e.g. to satisfy an EMS request), the EV may override the request and discharge up to underExcitedMaximumDischargePower to meet the minimum reactive power requirements. +
/// This corresponds to the WUnPF attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVUnderExcitedMaximumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "evUnderExcitedMaxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_under_excited_max_discharge_power: Option<f64>,
/// EV power factor when injecting (under excited) the minimum reactive power. +
/// Corresponds to the OvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVUnderExcitedPowerFactor
#[cfg_attr(feature = "serde", serde(rename = "evUnderExcitedPowerFactor"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_under_excited_power_factor: Option<f64>,
/// Rated maximum total apparent power, defined by min(EV, EVSE) in va.
/// Corresponds to the VAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_apparent_power: Option<f64>,
/// Rated maximum absorbed apparent power, defined by min(EV, EVSE) in va. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power: Option<f64>,
/// Rated maximum absorbed apparent power on phase L2, defined by min(EV, EVSE) in va.
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power_l2: Option<f64>,
/// Rated maximum absorbed apparent power on phase L3, defined by min(EV, EVSE) in va.
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power_l3: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars on phase L2. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power_l2: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars on phase L3. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power_l3: Option<f64>,
/// Rated maximum injected apparent power, defined by min(EV, EVSE) in va. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power: Option<f64>,
/// Rated maximum injected apparent power on phase L2, defined by min(EV, EVSE) in va. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power_l2: Option<f64>,
/// Rated maximum injected apparent power on phase L3, defined by min(EV, EVSE) in va. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power_l3: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars on phase L2. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power_l2: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars on phase L3. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power_l3: Option<f64>,
/// Maximum AC rms voltage, as defined by min(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "maxNominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_nominal_voltage: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars on phase L2. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power_l2: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars on phase L3. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power_l3: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in var on phase L2. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power_l2: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in var on phase L3. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power_l3: Option<f64>,
/// Minimum AC rms voltage, as defined by max(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "minNominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_nominal_voltage: Option<f64>,
/// Line voltage supported by EVSE and EV.
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "nominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub nominal_voltage: Option<f64>,
/// The nominal AC voltage (rms) offset between the Charging Station's electrical connection point and the utility’s point of common coupling. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVNominalVoltageOffset
#[cfg_attr(feature = "serde", serde(rename = "nominalVoltageOffset"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub nominal_voltage_offset: Option<f64>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for DERChargingParameters<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ev_islanding_detection_method {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evIslandingDetectionMethod"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evIslandingDetectionMethod")
})?;
}
}
if let Some(value) = &self.ev_supported_d_e_r_control {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evSupportedDERControl"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evSupportedDERControl")
})?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// *(2.1)* DERChargingParametersType is used in ChargingNeedsType during an ISO 15118-20 session for AC_BPT_DER to report the inverter settings related to DER control that were agreed between EVSE and EV.
///
/// Fields starting with "ev" contain values from the EV.
/// Other fields contain a value that is supported by both EV and EVSE.
///
/// DERChargingParametersType type is only relevant in case of an ISO 15118-20 AC_BPT_DER/AC_DER charging session.
///
/// NOTE: All these fields have values greater or equal to zero (i.e. are non-negative)
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DERChargingParameters<
CustomDataType = crate::NoCustomData,
const D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP: usize = 8usize,
const D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Maximum allowed duration of DC injection at level 1 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel1DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evDurationLevel1DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_duration_level1_d_c_injection: Option<f64>,
/// Maximum allowed duration of DC injection at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel2DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evDurationLevel2DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_duration_level2_d_c_injection: Option<f64>,
/// Hardware version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterHwVersion
#[cfg_attr(feature = "serde", serde(rename = "evInverterHwVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_hw_version: Option<heapless::String<50usize>>,
/// Manufacturer of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterManufacturer
#[cfg_attr(feature = "serde", serde(rename = "evInverterManufacturer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_manufacturer: Option<heapless::String<50usize>>,
/// Model name of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterModel
#[cfg_attr(feature = "serde", serde(rename = "evInverterModel"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_model: Option<heapless::String<50usize>>,
/// Serial number of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSerialNumber
#[cfg_attr(feature = "serde", serde(rename = "evInverterSerialNumber"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_serial_number: Option<heapless::String<50usize>>,
/// Software version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSwVersion
#[cfg_attr(feature = "serde", serde(rename = "evInverterSwVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_inverter_sw_version: Option<heapless::String<50usize>>,
/// Type of islanding detection method. Only mandatory when islanding detection is required at the site, as set in the ISO 15118 Service Details configuration. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVIslandingDetectionMethod
#[cfg_attr(feature = "serde", serde(rename = "evIslandingDetectionMethod"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_islanding_detection_method: Option<
heapless::Vec<
IslandingDetectionEnum,
D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP,
>,
>,
/// Time after which EV will trip if an island has been detected. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVIslandingTripTime
#[cfg_attr(feature = "serde", serde(rename = "evIslandingTripTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_islanding_trip_time: Option<f64>,
/// Maximum injected DC current allowed at level 1 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumLevel1DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evMaximumLevel1DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_maximum_level1_d_c_injection: Option<f64>,
/// Maximum injected DC current allowed at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumLevel2DCInjection
#[cfg_attr(feature = "serde", serde(rename = "evMaximumLevel2DCInjection"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_maximum_level2_d_c_injection: Option<f64>,
/// Rated maximum injected active power by EV, at specified over-excited power factor (overExcitedPowerFactor). +
/// It can also be defined as the rated maximum discharge power at the rated minimum injected reactive power value. This means that if the EV is providing reactive power support, and it is requested to discharge at max power (e.g. to satisfy an EMS request), the EV may override the request and discharge up to overExcitedMaximumDischargePower to meet the minimum reactive power requirements. +
/// Corresponds to the WOvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVOverExcitedMaximumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "evOverExcitedMaxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_over_excited_max_discharge_power: Option<f64>,
/// EV power factor when injecting (over excited) the minimum reactive power. +
/// Corresponds to the OvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVOverExcitedPowerFactor
#[cfg_attr(feature = "serde", serde(rename = "evOverExcitedPowerFactor"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_over_excited_power_factor: Option<f64>,
/// Measure of the susceptibility of the circuit to reactance, in Siemens (S). +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVReactiveSusceptance
#[cfg_attr(feature = "serde", serde(rename = "evReactiveSusceptance"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_reactive_susceptance: Option<f64>,
/// Total energy value, in Wh, that EV is allowed to provide during the entire V2G session. The value is independent of the V2X Cycling area. Once this value reaches the value of 0, the EV may block any attempt to discharge in order to protect the battery health.
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVSessionTotalDischargeEnergyAvailable
#[cfg_attr(
feature = "serde",
serde(rename = "evSessionTotalDischargeEnergyAvailable")
)]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_session_total_discharge_energy_available: Option<f64>,
/// DER control functions supported by EV. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType:DERControlFunctions (bitmap)
#[cfg_attr(feature = "serde", serde(rename = "evSupportedDERControl"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_supported_d_e_r_control: Option<
heapless::Vec<
DERControlEnum,
D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP,
>,
>,
/// Rated maximum injected active power by EV supported at specified under-excited power factor (EVUnderExcitedPowerFactor). +
/// It can also be defined as the rated maximum dischargePower at the rated minimum absorbed reactive power value.
/// This means that if the EV is providing reactive power support, and it is requested to discharge at max power (e.g. to satisfy an EMS request), the EV may override the request and discharge up to underExcitedMaximumDischargePower to meet the minimum reactive power requirements. +
/// This corresponds to the WUnPF attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVUnderExcitedMaximumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "evUnderExcitedMaxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_under_excited_max_discharge_power: Option<f64>,
/// EV power factor when injecting (under excited) the minimum reactive power. +
/// Corresponds to the OvPF attribute in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVUnderExcitedPowerFactor
#[cfg_attr(feature = "serde", serde(rename = "evUnderExcitedPowerFactor"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_under_excited_power_factor: Option<f64>,
/// Rated maximum total apparent power, defined by min(EV, EVSE) in va.
/// Corresponds to the VAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_apparent_power: Option<f64>,
/// Rated maximum absorbed apparent power, defined by min(EV, EVSE) in va. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power: Option<f64>,
/// Rated maximum absorbed apparent power on phase L2, defined by min(EV, EVSE) in va.
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power_l2: Option<f64>,
/// Rated maximum absorbed apparent power on phase L3, defined by min(EV, EVSE) in va.
/// Corresponds to the ChaVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeApparentPower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxChargeApparentPower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_apparent_power_l3: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars on phase L2. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power_l2: Option<f64>,
/// Rated maximum absorbed reactive power, defined by min(EV, EVSE), in vars on phase L3. +
/// Corresponds to the AvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumChargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxChargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_reactive_power_l3: Option<f64>,
/// Rated maximum injected apparent power, defined by min(EV, EVSE) in va. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power: Option<f64>,
/// Rated maximum injected apparent power on phase L2, defined by min(EV, EVSE) in va. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power_l2: Option<f64>,
/// Rated maximum injected apparent power on phase L3, defined by min(EV, EVSE) in va. +
/// Corresponds to the DisVAMaxRtg in IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeApparentPower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeApparentPower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_apparent_power_l3: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars on phase L2. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power_l2: Option<f64>,
/// Rated maximum injected reactive power, defined by min(EV, EVSE), in vars on phase L3. +
/// Corresponds to the IvarMax attribute in the IEC 61850. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumDischargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_reactive_power_l3: Option<f64>,
/// Maximum AC rms voltage, as defined by min(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "maxNominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_nominal_voltage: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars on phase L2. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power_l2: Option<f64>,
/// Rated minimum absorbed reactive power, defined by max(EV, EVSE), in vars on phase L3. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumChargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minChargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_reactive_power_l3: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in vars. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3,
/// in which case this field represents phase L1. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in var on phase L2. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power_l2: Option<f64>,
/// Rated minimum injected reactive power, defined by max(EV, EVSE), in var on phase L3. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumDischargeReactivePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minDischargeReactivePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_reactive_power_l3: Option<f64>,
/// Minimum AC rms voltage, as defined by max(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "minNominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_nominal_voltage: Option<f64>,
/// Line voltage supported by EVSE and EV.
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVNominalVoltage
#[cfg_attr(feature = "serde", serde(rename = "nominalVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub nominal_voltage: Option<f64>,
/// The nominal AC voltage (rms) offset between the Charging Station's electrical connection point and the utility’s point of common coupling. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVNominalVoltageOffset
#[cfg_attr(feature = "serde", serde(rename = "nominalVoltageOffset"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub nominal_voltage_offset: Option<f64>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP: usize,
const D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP: usize,
> crate::validate::Validate
for DERChargingParameters<
CustomDataType,
D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP,
D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ev_islanding_detection_method {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evIslandingDetectionMethod"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evIslandingDetectionMethod")
})?;
}
}
if let Some(value) = &self.ev_supported_d_e_r_control {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("evSupportedDERControl"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evSupportedDERControl")
})?;
}
}
Ok(())
}
}
/// *(2.1)* An entry in price schedule over time for which EV is willing to discharge.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVPriceRule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Cost per kWh.
#[cfg_attr(feature = "serde", serde(rename = "energyFee"))]
pub energy_fee: f64,
/// The EnergyFee applies between this value and the value of the PowerRangeStart of the subsequent EVPriceRule. If the power is below this value, the EnergyFee of the previous EVPriceRule applies. Negative values are used for discharging.
#[cfg_attr(feature = "serde", serde(rename = "powerRangeStart"))]
pub power_range_start: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for EVPriceRule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* An entry in price schedule over time for which EV is willing to discharge.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVAbsolutePriceScheduleEntry<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The amount of seconds of this entry.
pub duration: i64,
#[cfg_attr(feature = "serde", serde(rename = "evPriceRule"))]
pub ev_price_rule: heapless::Vec<EVPriceRule<CustomDataType>, 8usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for EVAbsolutePriceScheduleEntry<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.ev_price_rule.len(), 1usize)
.map_err(|error| error.in_field("evPriceRule"))?;
for (index, item) in self.ev_price_rule.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("evPriceRule"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// *(2.1)* Price schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVAbsolutePriceSchedule<CustomDataType = crate::NoCustomData> {
/// Currency code according to ISO 4217.
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evAbsolutePriceScheduleEntries"))]
pub ev_absolute_price_schedule_entries: alloc::vec::Vec<
EVAbsolutePriceScheduleEntry<CustomDataType>,
>,
/// ISO 15118-20 URN of price algorithm: Power, PeakPower, StackedEnergy.
#[cfg_attr(feature = "serde", serde(rename = "priceAlgorithm"))]
pub price_algorithm: alloc::string::String,
/// Starting point in time of the EVEnergyOffer.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for EVAbsolutePriceSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(
self.ev_absolute_price_schedule_entries.len(),
1usize,
)
.map_err(|error| error.in_field("evAbsolutePriceScheduleEntries"))?;
crate::validate::check_max_items(
self.ev_absolute_price_schedule_entries.len(),
1024usize,
)
.map_err(|error| error.in_field("evAbsolutePriceScheduleEntries"))?;
for (index, item) in self.ev_absolute_price_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evAbsolutePriceScheduleEntries")
})?;
}
crate::validate::check_max_length(&self.price_algorithm, 2000usize)
.map_err(|error| error.in_field("priceAlgorithm"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// *(2.1)* Price schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVAbsolutePriceSchedule<
CustomDataType = crate::NoCustomData,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize = 8usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
> {
/// Currency code according to ISO 4217.
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evAbsolutePriceScheduleEntries"))]
pub ev_absolute_price_schedule_entries: heapless::Vec<
EVAbsolutePriceScheduleEntry<CustomDataType>,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
>,
/// ISO 15118-20 URN of price algorithm: Power, PeakPower, StackedEnergy.
#[cfg_attr(feature = "serde", serde(rename = "priceAlgorithm"))]
pub price_algorithm: heapless::String<
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
>,
/// Starting point in time of the EVEnergyOffer.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
> crate::validate::Validate
for EVAbsolutePriceSchedule<
CustomDataType,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(
self.ev_absolute_price_schedule_entries.len(),
1usize,
)
.map_err(|error| error.in_field("evAbsolutePriceScheduleEntries"))?;
crate::validate::check_max_items(
self.ev_absolute_price_schedule_entries.len(),
1024usize,
)
.map_err(|error| error.in_field("evAbsolutePriceScheduleEntries"))?;
for (index, item) in self.ev_absolute_price_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evAbsolutePriceScheduleEntries")
})?;
}
crate::validate::check_max_length(&self.price_algorithm, 2000usize)
.map_err(|error| error.in_field("priceAlgorithm"))?;
Ok(())
}
}
/// *(2.1)* An entry in schedule of the energy amount over time that EV is willing to discharge. A negative value indicates the willingness to discharge under specific conditions, a positive value indicates that the EV currently is not able to offer energy to discharge.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVPowerScheduleEntry<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The duration of this entry.
pub duration: i64,
/// Defines maximum amount of power for the duration of this EVPowerScheduleEntry to be discharged from the EV battery through EVSE power outlet. Negative values are used for discharging.
pub power: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for EVPowerScheduleEntry<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// *(2.1)* Schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVPowerSchedule<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evPowerScheduleEntries"))]
pub ev_power_schedule_entries: alloc::vec::Vec<EVPowerScheduleEntry<CustomDataType>>,
/// The time that defines the starting point for the EVEnergyOffer.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for EVPowerSchedule<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.ev_power_schedule_entries.len(), 1usize)
.map_err(|error| error.in_field("evPowerScheduleEntries"))?;
crate::validate::check_max_items(self.ev_power_schedule_entries.len(), 1024usize)
.map_err(|error| error.in_field("evPowerScheduleEntries"))?;
for (index, item) in self.ev_power_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evPowerScheduleEntries")
})?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// *(2.1)* Schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVPowerSchedule<
CustomDataType = crate::NoCustomData,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evPowerScheduleEntries"))]
pub ev_power_schedule_entries: heapless::Vec<
EVPowerScheduleEntry<CustomDataType>,
E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP,
>,
/// The time that defines the starting point for the EVEnergyOffer.
#[cfg_attr(feature = "serde", serde(rename = "timeAnchor"))]
pub time_anchor: crate::OcppTimestamp,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize,
> crate::validate::Validate
for EVPowerSchedule<CustomDataType, E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.ev_power_schedule_entries.len(), 1usize)
.map_err(|error| error.in_field("evPowerScheduleEntries"))?;
crate::validate::check_max_items(self.ev_power_schedule_entries.len(), 1024usize)
.map_err(|error| error.in_field("evPowerScheduleEntries"))?;
for (index, item) in self.ev_power_schedule_entries.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("evPowerScheduleEntries")
})?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// *(2.1)* A schedule of the energy amount over time that EV is willing to discharge. A negative value indicates the willingness to discharge under specific conditions, a positive value indicates that the EV currently is not able to offer energy to discharge.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVEnergyOffer<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evAbsolutePriceSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_absolute_price_schedule: Option<EVAbsolutePriceSchedule<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "evPowerSchedule"))]
pub ev_power_schedule: EVPowerSchedule<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for EVEnergyOffer<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ev_absolute_price_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evAbsolutePriceSchedule"))?;
}
crate::validate::Validate::validate(&self.ev_power_schedule)
.map_err(|error| error.in_field("evPowerSchedule"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// *(2.1)* A schedule of the energy amount over time that EV is willing to discharge. A negative value indicates the willingness to discharge under specific conditions, a positive value indicates that the EV currently is not able to offer energy to discharge.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EVEnergyOffer<
CustomDataType = crate::NoCustomData,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize = 8usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "evAbsolutePriceSchedule"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_absolute_price_schedule: Option<
EVAbsolutePriceSchedule<
CustomDataType,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "evPowerSchedule"))]
pub ev_power_schedule: EVPowerSchedule<
CustomDataType,
E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize,
> crate::validate::Validate
for EVEnergyOffer<
CustomDataType,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ev_absolute_price_schedule {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evAbsolutePriceSchedule"))?;
}
crate::validate::Validate::validate(&self.ev_power_schedule)
.map_err(|error| error.in_field("evPowerSchedule"))?;
Ok(())
}
}
/// *(2.1)* Value of EVCC indicates that EV determines min/target SOC and departure time. +
/// A value of EVCC_SECC indicates that charging station or CSMS may also update min/target SOC and departure time. +
/// *ISO 15118-20:* +
/// ServiceSelectionReq(SelectedEnergyTransferService)
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MobilityNeedsModeEnum {
EVCC,
#[cfg_attr(feature = "serde", serde(rename = "EVCC_SECC"))]
EVCCSECC,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MobilityNeedsModeEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Charging parameters for ISO 15118-20, also supporting V2X charging/discharging.+
/// All values are greater or equal to zero, with the exception of EVMinEnergyRequest, EVMaxEnergyRequest, EVTargetEnergyRequest, EVMinV2XEnergyRequest and EVMaxV2XEnergyRequest.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct V2XChargingParameters<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Energy to maximum state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVMaximumEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "evMaxEnergyRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_max_energy_request: Option<f64>,
/// Energy (in Wh) to maximum state of charge for cycling (V2X) activity.
/// Negative value indicates that current state of charge is above V2X range.
/// Relates to:
/// *ISO 15118-20*: Dynamic_SEReqControlModeType: EVMaximumV2XEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "evMaxV2XEnergyRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_max_v2_x_energy_request: Option<f64>,
/// Energy to minimum allowed state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVMinimumEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "evMinEnergyRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_min_energy_request: Option<f64>,
/// Energy (in Wh) to minimum state of charge for cycling (V2X) activity.
/// Positive value means that current state of charge is below V2X range.
/// Relates to:
/// *ISO 15118-20*: Dynamic_SEReqControlModeType: EVMinimumV2XEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "evMinV2XEnergyRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_min_v2_x_energy_request: Option<f64>,
/// Energy to requested state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVTargetEnergyRequest
#[cfg_attr(feature = "serde", serde(rename = "evTargetEnergyRequest"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_target_energy_request: Option<f64>,
/// Maximum charge current in A, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumChargeCurrent
#[cfg_attr(feature = "serde", serde(rename = "maxChargeCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_current: Option<f64>,
/// Maximum charge (absorbed) power in W, defined by min(EV, EVSE) at unity power factor. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
/// It corresponds to the ChaWMax attribute in the IEC 61850.
/// It is usually equivalent to the rated apparent power of the EV when discharging (ChaVAMax) in IEC 61850. +
///
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumChargePower
#[cfg_attr(feature = "serde", serde(rename = "maxChargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_power: Option<f64>,
/// Maximum charge power on phase L2 in W, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumChargePower_L2
#[cfg_attr(feature = "serde", serde(rename = "maxChargePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_power_l2: Option<f64>,
/// Maximum charge power on phase L3 in W, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumChargePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxChargePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_charge_power_l3: Option<f64>,
/// Maximum discharge current in A, defined by min(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumDischargeCurrent
#[cfg_attr(feature = "serde", serde(rename = "maxDischargeCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_current: Option<f64>,
/// Maximum discharge (injected) power in W, defined by min(EV, EVSE) at unity power factor. Value >= 0.
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "maxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_power: Option<f64>,
/// Maximum discharge power on phase L2 in W, defined by min(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumDischargePowe_L2
#[cfg_attr(feature = "serde", serde(rename = "maxDischargePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_power_l2: Option<f64>,
/// Maximum discharge power on phase L3 in W, defined by min(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMaximumDischargePower_L3
#[cfg_attr(feature = "serde", serde(rename = "maxDischargePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_discharge_power_l3: Option<f64>,
/// Maximum voltage in V, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumVoltage
#[cfg_attr(feature = "serde", serde(rename = "maxVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_voltage: Option<f64>,
/// Minimum charge current in A, defined by max(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumChargeCurrent
#[cfg_attr(feature = "serde", serde(rename = "minChargeCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_current: Option<f64>,
/// Minimum charge power in W, defined by max(EV, EVSE).
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumChargePower
#[cfg_attr(feature = "serde", serde(rename = "minChargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_power: Option<f64>,
/// Minimum charge power on phase L2 in W, defined by max(EV, EVSE).
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumChargePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minChargePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_power_l2: Option<f64>,
/// Minimum charge power on phase L3 in W, defined by max(EV, EVSE).
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumChargePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minChargePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_charge_power_l3: Option<f64>,
/// Minimum discharge current in A, defined by max(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumDischargeCurrent
#[cfg_attr(feature = "serde", serde(rename = "minDischargeCurrent"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_current: Option<f64>,
/// Minimum discharge (injected) power in W, defined by max(EV, EVSE) at unity power factor. Value >= 0. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1. +
/// It corresponds to the WMax attribute in the IEC 61850.
/// It is usually equivalent to the rated apparent power of the EV when discharging (VAMax attribute in the IEC 61850).
///
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumDischargePower
#[cfg_attr(feature = "serde", serde(rename = "minDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_power: Option<f64>,
/// Minimum discharge power on phase L2 in W, defined by max(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumDischargePower_L2
#[cfg_attr(feature = "serde", serde(rename = "minDischargePower_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_power_l2: Option<f64>,
/// Minimum discharge power on phase L3 in W, defined by max(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_AC/DC_CPDReqEnergyTransferModeType: EVMinimumDischargePower_L3
#[cfg_attr(feature = "serde", serde(rename = "minDischargePower_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_discharge_power_l3: Option<f64>,
/// Minimum voltage in V, defined by max(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumVoltage
#[cfg_attr(feature = "serde", serde(rename = "minVoltage"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_voltage: Option<f64>,
/// Target state of charge at departure as percentage.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: TargetSOC
#[cfg_attr(feature = "serde", serde(rename = "targetSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub target_so_c: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for V2XChargingParameters<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.target_so_c {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("targetSoC"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("targetSoC"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingNeeds<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "acChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ac_charging_parameters: Option<ACChargingParameters<CustomDataType>>,
/// *(2.1)* Modes of energy transfer that are marked as available by EV.
#[cfg_attr(feature = "serde", serde(rename = "availableEnergyTransfer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub available_energy_transfer: Option<alloc::vec::Vec<EnergyTransferModeEnum>>,
#[cfg_attr(feature = "serde", serde(rename = "controlMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub control_mode: Option<ControlModeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "dcChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dc_charging_parameters: Option<DCChargingParameters<CustomDataType>>,
/// Estimated departure time of the EV. +
/// *ISO 15118-2:* AC/DC_EVChargeParameterType: DepartureTime +
/// *ISO 15118-20:* Dynamic/Scheduled_SEReqControlModeType: DepartureTIme
#[cfg_attr(feature = "serde", serde(rename = "departureTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub departure_time: Option<crate::OcppTimestamp>,
#[cfg_attr(feature = "serde", serde(rename = "derChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub der_charging_parameters: Option<DERChargingParameters<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "evEnergyOffer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_energy_offer: Option<EVEnergyOffer<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "mobilityNeedsMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub mobility_needs_mode: Option<MobilityNeedsModeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "requestedEnergyTransfer"))]
pub requested_energy_transfer: EnergyTransferModeEnum,
#[cfg_attr(feature = "serde", serde(rename = "v2xChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_charging_parameters: Option<V2XChargingParameters<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ChargingNeeds<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ac_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("acChargingParameters"))?;
}
if let Some(value) = &self.available_energy_transfer {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("availableEnergyTransfer"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("availableEnergyTransfer")
})?;
}
}
if let Some(value) = &self.control_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("controlMode"))?;
}
if let Some(value) = &self.dc_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("dcChargingParameters"))?;
}
if let Some(value) = &self.der_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("derChargingParameters"))?;
}
if let Some(value) = &self.ev_energy_offer {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evEnergyOffer"))?;
}
if let Some(value) = &self.mobility_needs_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("mobilityNeedsMode"))?;
}
crate::validate::Validate::validate(&self.requested_energy_transfer)
.map_err(|error| error.in_field("requestedEnergyTransfer"))?;
if let Some(value) = &self.v2x_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("v2xChargingParameters"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingNeeds<
CustomDataType = crate::NoCustomData,
const CHARGING_NEEDS_AVAILABLE_ENERGY_TRANSFER_CAP: usize = 8usize,
const D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP: usize = 8usize,
const D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP: usize = 8usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize = 8usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "acChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ac_charging_parameters: Option<ACChargingParameters<CustomDataType>>,
/// *(2.1)* Modes of energy transfer that are marked as available by EV.
#[cfg_attr(feature = "serde", serde(rename = "availableEnergyTransfer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub available_energy_transfer: Option<
heapless::Vec<
EnergyTransferModeEnum,
CHARGING_NEEDS_AVAILABLE_ENERGY_TRANSFER_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "controlMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub control_mode: Option<ControlModeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "dcChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dc_charging_parameters: Option<DCChargingParameters<CustomDataType>>,
/// Estimated departure time of the EV. +
/// *ISO 15118-2:* AC/DC_EVChargeParameterType: DepartureTime +
/// *ISO 15118-20:* Dynamic/Scheduled_SEReqControlModeType: DepartureTIme
#[cfg_attr(feature = "serde", serde(rename = "departureTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub departure_time: Option<crate::OcppTimestamp>,
#[cfg_attr(feature = "serde", serde(rename = "derChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub der_charging_parameters: Option<
DERChargingParameters<
CustomDataType,
D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP,
D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "evEnergyOffer"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ev_energy_offer: Option<
EVEnergyOffer<
CustomDataType,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "mobilityNeedsMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub mobility_needs_mode: Option<MobilityNeedsModeEnum>,
#[cfg_attr(feature = "serde", serde(rename = "requestedEnergyTransfer"))]
pub requested_energy_transfer: EnergyTransferModeEnum,
#[cfg_attr(feature = "serde", serde(rename = "v2xChargingParameters"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v2x_charging_parameters: Option<V2XChargingParameters<CustomDataType>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const CHARGING_NEEDS_AVAILABLE_ENERGY_TRANSFER_CAP: usize,
const D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP: usize,
const D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP: usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP: usize,
const E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
const E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP: usize,
> crate::validate::Validate
for ChargingNeeds<
CustomDataType,
CHARGING_NEEDS_AVAILABLE_ENERGY_TRANSFER_CAP,
D_E_R_CHARGING_PARAMETERS_EV_ISLANDING_DETECTION_METHOD_CAP,
D_E_R_CHARGING_PARAMETERS_EV_SUPPORTED_D_E_R_CONTROL_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_EV_ABSOLUTE_PRICE_SCHEDULE_ENTRIES_CAP,
E_V_ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
E_V_POWER_SCHEDULE_EV_POWER_SCHEDULE_ENTRIES_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.ac_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("acChargingParameters"))?;
}
if let Some(value) = &self.available_energy_transfer {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("availableEnergyTransfer"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| {
error.in_index(index).in_field("availableEnergyTransfer")
})?;
}
}
if let Some(value) = &self.control_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("controlMode"))?;
}
if let Some(value) = &self.dc_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("dcChargingParameters"))?;
}
if let Some(value) = &self.der_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("derChargingParameters"))?;
}
if let Some(value) = &self.ev_energy_offer {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("evEnergyOffer"))?;
}
if let Some(value) = &self.mobility_needs_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("mobilityNeedsMode"))?;
}
crate::validate::Validate::validate(&self.requested_energy_transfer)
.map_err(|error| error.in_field("requestedEnergyTransfer"))?;
if let Some(value) = &self.v2x_charging_parameters {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("v2xChargingParameters"))?;
}
Ok(())
}
}
/// Returns whether the CSMS has been able to process the message successfully. It does not imply that the evChargingNeeds can be met with the current charging profile.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NotifyEVChargingNeedsStatusEnum {
Accepted,
Rejected,
Processing,
NoChargingProfile,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for NotifyEVChargingNeedsStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Specifies the event notification type of the message.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EventNotificationEnum {
HardWiredNotification,
HardWiredMonitor,
PreconfiguredMonitor,
CustomMonitor,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for EventNotificationEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of trigger for this event, e.g. exceeding a threshold value.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EventTriggerEnum {
Alerting,
Delta,
Periodic,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for EventTriggerEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Class to report an event notification for a component-variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EventData<CustomDataType = crate::NoCustomData> {
/// Actual value (_attributeType_ Actual) of the variable.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "actualValue"))]
pub actual_value: alloc::string::String,
/// Refers to the Id of an event that is considered to be the cause for this event.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cause: Option<i64>,
/// _Cleared_ is set to true to report the clearing of a monitored situation, i.e. a 'return to normal'.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cleared: Option<bool>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Identifies the event. This field can be referred to as a cause by other events.
#[cfg_attr(feature = "serde", serde(rename = "eventId"))]
pub event_id: i64,
#[cfg_attr(feature = "serde", serde(rename = "eventNotificationType"))]
pub event_notification_type: EventNotificationEnum,
/// *(2.1)* Severity associated with the monitor in _variableMonitoringId_ or with the hardwired notification.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub severity: Option<i64>,
/// Technical (error) code as reported by component.
#[cfg_attr(feature = "serde", serde(rename = "techCode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tech_code: Option<heapless::String<50usize>>,
/// Technical detail information as reported by component.
#[cfg_attr(feature = "serde", serde(rename = "techInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tech_info: Option<heapless::String<500usize>>,
/// Timestamp of the moment the report was generated.
pub timestamp: crate::OcppTimestamp,
/// If an event notification is linked to a specific transaction, this field can be used to specify its transactionId.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
pub trigger: EventTriggerEnum,
pub variable: Variable<CustomDataType>,
/// Identifies the VariableMonitoring which triggered the event.
#[cfg_attr(feature = "serde", serde(rename = "variableMonitoringId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variable_monitoring_id: Option<i64>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for EventData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.actual_value, 2500usize)
.map_err(|error| error.in_field("actualValue"))?;
if let Some(value) = self.cause {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("cause"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::check_min_i64(self.event_id, 0i64)
.map_err(|error| error.in_field("eventId"))?;
crate::validate::Validate::validate(&self.event_notification_type)
.map_err(|error| error.in_field("eventNotificationType"))?;
if let Some(value) = self.severity {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("severity"))?;
}
crate::validate::Validate::validate(&self.trigger)
.map_err(|error| error.in_field("trigger"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
if let Some(value) = self.variable_monitoring_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("variableMonitoringId"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Class to report an event notification for a component-variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EventData<
CustomDataType = crate::NoCustomData,
const EVENT_DATA_ACTUAL_VALUE_CAP: usize = 1024usize,
> {
/// Actual value (_attributeType_ Actual) of the variable.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "actualValue"))]
pub actual_value: heapless::String<EVENT_DATA_ACTUAL_VALUE_CAP>,
/// Refers to the Id of an event that is considered to be the cause for this event.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cause: Option<i64>,
/// _Cleared_ is set to true to report the clearing of a monitored situation, i.e. a 'return to normal'.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub cleared: Option<bool>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Identifies the event. This field can be referred to as a cause by other events.
#[cfg_attr(feature = "serde", serde(rename = "eventId"))]
pub event_id: i64,
#[cfg_attr(feature = "serde", serde(rename = "eventNotificationType"))]
pub event_notification_type: EventNotificationEnum,
/// *(2.1)* Severity associated with the monitor in _variableMonitoringId_ or with the hardwired notification.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub severity: Option<i64>,
/// Technical (error) code as reported by component.
#[cfg_attr(feature = "serde", serde(rename = "techCode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tech_code: Option<heapless::String<50usize>>,
/// Technical detail information as reported by component.
#[cfg_attr(feature = "serde", serde(rename = "techInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tech_info: Option<heapless::String<500usize>>,
/// Timestamp of the moment the report was generated.
pub timestamp: crate::OcppTimestamp,
/// If an event notification is linked to a specific transaction, this field can be used to specify its transactionId.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
pub trigger: EventTriggerEnum,
pub variable: Variable<CustomDataType>,
/// Identifies the VariableMonitoring which triggered the event.
#[cfg_attr(feature = "serde", serde(rename = "variableMonitoringId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variable_monitoring_id: Option<i64>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const EVENT_DATA_ACTUAL_VALUE_CAP: usize> crate::validate::Validate
for EventData<CustomDataType, EVENT_DATA_ACTUAL_VALUE_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.actual_value, 2500usize)
.map_err(|error| error.in_field("actualValue"))?;
if let Some(value) = self.cause {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("cause"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::check_min_i64(self.event_id, 0i64)
.map_err(|error| error.in_field("eventId"))?;
crate::validate::Validate::validate(&self.event_notification_type)
.map_err(|error| error.in_field("eventNotificationType"))?;
if let Some(value) = self.severity {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("severity"))?;
}
crate::validate::Validate::validate(&self.trigger)
.map_err(|error| error.in_field("trigger"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
if let Some(value) = self.variable_monitoring_id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("variableMonitoringId"))?;
}
Ok(())
}
}
/// The type of this monitor, e.g. a threshold, delta or periodic monitor.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MonitorEnum {
UpperThreshold,
LowerThreshold,
Delta,
Periodic,
PeriodicClockAligned,
TargetDelta,
TargetDeltaRelative,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MonitorEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// A monitoring setting for a variable.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableMonitoring<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "eventNotificationType"))]
pub event_notification_type: EventNotificationEnum,
/// Identifies the monitor.
pub id: i64,
/// The severity that will be assigned to an event that is triggered by this monitor. The severity range is 0-9, with 0 as the highest and 9 as the lowest severity level.
///
/// The severity levels have the following meaning: +
/// *0-Danger* +
/// Indicates lives are potentially in danger. Urgent attention is needed and action should be taken immediately. +
/// *1-Hardware Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to Hardware issues. Action is required. +
/// *2-System Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to software or minor hardware issues. Action is required. +
/// *3-Critical* +
/// Indicates a critical error. Action is required. +
/// *4-Error* +
/// Indicates a non-urgent error. Action is required. +
/// *5-Alert* +
/// Indicates an alert event. Default severity for any type of monitoring event. +
/// *6-Warning* +
/// Indicates a warning event. Action may be required. +
/// *7-Notice* +
/// Indicates an unusual event. No immediate action is required. +
/// *8-Informational* +
/// Indicates a regular operational event. May be used for reporting, measuring throughput, etc. No action is required. +
/// *9-Debug* +
/// Indicates information useful to developers for debugging, not useful during operations.
pub severity: i64,
/// Monitor only active when a transaction is ongoing on a component relevant to this transaction.
pub transaction: bool,
pub r#type: MonitorEnum,
/// Value for threshold or delta monitoring.
/// For Periodic or PeriodicClockAligned this is the interval in seconds.
pub value: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for VariableMonitoring<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.event_notification_type)
.map_err(|error| error.in_field("eventNotificationType"))?;
crate::validate::check_min_i64(self.id, 0i64)
.map_err(|error| error.in_field("id"))?;
crate::validate::check_min_i64(self.severity, 0i64)
.map_err(|error| error.in_field("severity"))?;
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Class to hold parameters of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MonitoringData<CustomDataType = crate::NoCustomData> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "variableMonitoring"))]
pub variable_monitoring: alloc::vec::Vec<VariableMonitoring<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for MonitoringData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
crate::validate::check_min_items(self.variable_monitoring.len(), 1usize)
.map_err(|error| error.in_field("variableMonitoring"))?;
for (index, item) in self.variable_monitoring.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("variableMonitoring"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Class to hold parameters of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MonitoringData<
CustomDataType = crate::NoCustomData,
const MONITORING_DATA_VARIABLE_MONITORING_CAP: usize = 8usize,
> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "variableMonitoring"))]
pub variable_monitoring: heapless::Vec<
VariableMonitoring<CustomDataType>,
MONITORING_DATA_VARIABLE_MONITORING_CAP,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const MONITORING_DATA_VARIABLE_MONITORING_CAP: usize,
> crate::validate::Validate
for MonitoringData<CustomDataType, MONITORING_DATA_VARIABLE_MONITORING_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
crate::validate::check_min_items(self.variable_monitoring.len(), 1usize)
.map_err(|error| error.in_field("variableMonitoring"))?;
for (index, item) in self.variable_monitoring.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("variableMonitoring"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StreamDataElement<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Offset relative to _basetime_ of this message. _basetime_ + _t_ is timestamp of recorded value.
pub t: f64,
pub v: alloc::string::String,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for StreamDataElement<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.v, 2500usize)
.map_err(|error| error.in_field("v"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StreamDataElement<
CustomDataType = crate::NoCustomData,
const STREAM_DATA_ELEMENT_V_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Offset relative to _basetime_ of this message. _basetime_ + _t_ is timestamp of recorded value.
pub t: f64,
pub v: heapless::String<STREAM_DATA_ELEMENT_V_CAP>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const STREAM_DATA_ELEMENT_V_CAP: usize> crate::validate::Validate
for StreamDataElement<CustomDataType, STREAM_DATA_ELEMENT_V_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.v, 2500usize)
.map_err(|error| error.in_field("v"))?;
Ok(())
}
}
/// Defines the mutability of this attribute. Default is ReadWrite when omitted.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MutabilityEnum {
ReadOnly,
WriteOnly,
ReadWrite,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MutabilityEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Attribute data of a variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableAttribute<CustomDataType = crate::NoCustomData> {
/// If true, value that will never be changed by the Charging Station at runtime. Default when omitted is false.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub constant: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub mutability: Option<MutabilityEnum>,
/// If true, value will be persistent across system reboots or power down. Default when omitted is false.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub persistent: Option<bool>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub r#type: Option<AttributeEnum>,
/// Value of the attribute. May only be omitted when mutability is set to 'WriteOnly'.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub value: Option<alloc::string::String>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for VariableAttribute<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.mutability {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("mutability"))?;
}
if let Some(value) = &self.r#type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("type"))?;
}
if let Some(value) = &self.value {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("value"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Attribute data of a variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableAttribute<
CustomDataType = crate::NoCustomData,
const VARIABLE_ATTRIBUTE_VALUE_CAP: usize = 1024usize,
> {
/// If true, value that will never be changed by the Charging Station at runtime. Default when omitted is false.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub constant: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub mutability: Option<MutabilityEnum>,
/// If true, value will be persistent across system reboots or power down. Default when omitted is false.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub persistent: Option<bool>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub r#type: Option<AttributeEnum>,
/// Value of the attribute. May only be omitted when mutability is set to 'WriteOnly'.
///
/// The Configuration Variable <<configkey-reporting-value-size,ReportingValueSize>> can be used to limit GetVariableResult.attributeValue, VariableAttribute.value and EventData.actualValue. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub value: Option<heapless::String<VARIABLE_ATTRIBUTE_VALUE_CAP>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const VARIABLE_ATTRIBUTE_VALUE_CAP: usize> crate::validate::Validate
for VariableAttribute<CustomDataType, VARIABLE_ATTRIBUTE_VALUE_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.mutability {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("mutability"))?;
}
if let Some(value) = &self.r#type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("type"))?;
}
if let Some(value) = &self.value {
crate::validate::check_max_length(value, 2500usize)
.map_err(|error| error.in_field("value"))?;
}
Ok(())
}
}
/// Data type of this variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DataEnum {
#[cfg_attr(feature = "serde", serde(rename = "string"))]
String,
#[cfg_attr(feature = "serde", serde(rename = "decimal"))]
Decimal,
#[cfg_attr(feature = "serde", serde(rename = "integer"))]
Integer,
#[cfg_attr(feature = "serde", serde(rename = "dateTime"))]
DateTime,
#[cfg_attr(feature = "serde", serde(rename = "boolean"))]
Boolean,
OptionList,
SequenceList,
MemberList,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DataEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Fixed read-only parameters of a variable.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableCharacteristics<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "dataType"))]
pub data_type: DataEnum,
/// *(2.1)* Maximum number of elements from _valuesList_ that are supported as _attributeValue_.
#[cfg_attr(feature = "serde", serde(rename = "maxElements"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_elements: Option<i64>,
/// Maximum possible value of this variable. When the datatype of this Variable is String, OptionList, SequenceList or MemberList, this field defines the maximum length of the (CSV) string.
#[cfg_attr(feature = "serde", serde(rename = "maxLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_limit: Option<f64>,
/// Minimum possible value of this variable.
#[cfg_attr(feature = "serde", serde(rename = "minLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_limit: Option<f64>,
/// Flag indicating if this variable supports monitoring.
#[cfg_attr(feature = "serde", serde(rename = "supportsMonitoring"))]
pub supports_monitoring: bool,
/// Unit of the variable. When the transmitted value has a unit, this field SHALL be included.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unit: Option<heapless::String<16usize>>,
/// Mandatory when _dataType_ = OptionList, MemberList or SequenceList. In that case _valuesList_ specifies the allowed values for the type.
///
/// The length of this field can be limited by DeviceDataCtrlr.ConfigurationValueSize.
///
/// * OptionList: The (Actual) Variable value must be a single value from the reported (CSV) enumeration list.
///
/// * MemberList: The (Actual) Variable value may be an (unordered) (sub-)set of the reported (CSV) valid values list.
///
/// * SequenceList: The (Actual) Variable value may be an ordered (priority, etc) (sub-)set of the reported (CSV) valid values.
///
/// This is a comma separated list.
///
/// The Configuration Variable <<configkey-configuration-value-size,ConfigurationValueSize>> can be used to limit SetVariableData.attributeValue and VariableCharacteristics.valuesList. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "valuesList"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub values_list: Option<alloc::string::String>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for VariableCharacteristics<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.data_type)
.map_err(|error| error.in_field("dataType"))?;
if let Some(value) = self.max_elements {
crate::validate::check_min_i64(value, 1i64)
.map_err(|error| error.in_field("maxElements"))?;
}
if let Some(value) = &self.values_list {
crate::validate::check_max_length(value, 1000usize)
.map_err(|error| error.in_field("valuesList"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Fixed read-only parameters of a variable.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableCharacteristics<
CustomDataType = crate::NoCustomData,
const VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP: usize = 1000usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "dataType"))]
pub data_type: DataEnum,
/// *(2.1)* Maximum number of elements from _valuesList_ that are supported as _attributeValue_.
#[cfg_attr(feature = "serde", serde(rename = "maxElements"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_elements: Option<i64>,
/// Maximum possible value of this variable. When the datatype of this Variable is String, OptionList, SequenceList or MemberList, this field defines the maximum length of the (CSV) string.
#[cfg_attr(feature = "serde", serde(rename = "maxLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_limit: Option<f64>,
/// Minimum possible value of this variable.
#[cfg_attr(feature = "serde", serde(rename = "minLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_limit: Option<f64>,
/// Flag indicating if this variable supports monitoring.
#[cfg_attr(feature = "serde", serde(rename = "supportsMonitoring"))]
pub supports_monitoring: bool,
/// Unit of the variable. When the transmitted value has a unit, this field SHALL be included.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unit: Option<heapless::String<16usize>>,
/// Mandatory when _dataType_ = OptionList, MemberList or SequenceList. In that case _valuesList_ specifies the allowed values for the type.
///
/// The length of this field can be limited by DeviceDataCtrlr.ConfigurationValueSize.
///
/// * OptionList: The (Actual) Variable value must be a single value from the reported (CSV) enumeration list.
///
/// * MemberList: The (Actual) Variable value may be an (unordered) (sub-)set of the reported (CSV) valid values list.
///
/// * SequenceList: The (Actual) Variable value may be an ordered (priority, etc) (sub-)set of the reported (CSV) valid values.
///
/// This is a comma separated list.
///
/// The Configuration Variable <<configkey-configuration-value-size,ConfigurationValueSize>> can be used to limit SetVariableData.attributeValue and VariableCharacteristics.valuesList. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "valuesList"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub values_list: Option<heapless::String<VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP: usize,
> crate::validate::Validate
for VariableCharacteristics<CustomDataType, VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.data_type)
.map_err(|error| error.in_field("dataType"))?;
if let Some(value) = self.max_elements {
crate::validate::check_min_i64(value, 1i64)
.map_err(|error| error.in_field("maxElements"))?;
}
if let Some(value) = &self.values_list {
crate::validate::check_max_length(value, 1000usize)
.map_err(|error| error.in_field("valuesList"))?;
}
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Class to report components, variables and variable attributes and characteristics.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ReportData<CustomDataType = crate::NoCustomData> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "variableAttribute"))]
pub variable_attribute: heapless::Vec<VariableAttribute<CustomDataType>, 4usize>,
#[cfg_attr(feature = "serde", serde(rename = "variableCharacteristics"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variable_characteristics: Option<VariableCharacteristics<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ReportData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
crate::validate::check_min_items(self.variable_attribute.len(), 1usize)
.map_err(|error| error.in_field("variableAttribute"))?;
for (index, item) in self.variable_attribute.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("variableAttribute"))?;
}
if let Some(value) = &self.variable_characteristics {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("variableCharacteristics"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Class to report components, variables and variable attributes and characteristics.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ReportData<
CustomDataType = crate::NoCustomData,
const VARIABLE_ATTRIBUTE_VALUE_CAP: usize = 1024usize,
const VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP: usize = 1000usize,
> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "variableAttribute"))]
pub variable_attribute: heapless::Vec<
VariableAttribute<CustomDataType, VARIABLE_ATTRIBUTE_VALUE_CAP>,
4usize,
>,
#[cfg_attr(feature = "serde", serde(rename = "variableCharacteristics"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variable_characteristics: Option<
VariableCharacteristics<CustomDataType, VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP>,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const VARIABLE_ATTRIBUTE_VALUE_CAP: usize,
const VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP: usize,
> crate::validate::Validate
for ReportData<
CustomDataType,
VARIABLE_ATTRIBUTE_VALUE_CAP,
VARIABLE_CHARACTERISTICS_VALUES_LIST_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
crate::validate::check_min_items(self.variable_attribute.len(), 1usize)
.map_err(|error| error.in_field("variableAttribute"))?;
for (index, item) in self.variable_attribute.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("variableAttribute"))?;
}
if let Some(value) = &self.variable_characteristics {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("variableCharacteristics"))?;
}
Ok(())
}
}
/// The status of the settlement attempt.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PaymentStatusEnum {
Settled,
Canceled,
Rejected,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PaymentStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* A generic address format.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Address<CustomDataType = crate::NoCustomData> {
/// Address line 1
pub address1: heapless::String<100usize>,
/// Address line 2
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub address2: Option<heapless::String<100usize>>,
/// City
pub city: heapless::String<100usize>,
/// Country name
pub country: heapless::String<50usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Name of person/company
pub name: heapless::String<50usize>,
/// Postal code
#[cfg_attr(feature = "serde", serde(rename = "postalCode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub postal_code: Option<heapless::String<20usize>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Address<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains the progress status of the publishfirmware
/// installation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PublishFirmwareStatusEnum {
Idle,
DownloadScheduled,
Downloading,
Downloaded,
Published,
DownloadFailed,
DownloadPaused,
InvalidChecksum,
ChecksumVerified,
PublishFailed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PublishFirmwareStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Updates to a ChargingSchedulePeriodType for dynamic charging profiles.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingScheduleUpdate<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Limit in _chargingRateUnit_ that the EV is allowed to discharge with. Note, these are negative values in order to be consistent with _setpoint_, which can be positive and negative. +
/// For AC this field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L2 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l2: Option<f64>,
/// *(2.1)* Limit in _chargingRateUnit_ on phase L3 that the EV is allowed to discharge with.
#[cfg_attr(feature = "serde", serde(rename = "dischargeLimit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub discharge_limit_l3: Option<f64>,
/// Optional only when not required by the _operationMode_, as in CentralSetpoint, ExternalSetpoint, ExternalLimits, LocalFrequency, LocalLoadBalancing. +
/// Charging rate limit during the schedule period, in the applicable _chargingRateUnit_.
/// This SHOULD be a non-negative value; a negative value is only supported for backwards compatibility with older systems that use a negative value to specify a discharging limit.
/// For AC this field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit: Option<f64>,
/// *(2.1)* Charging rate limit on phase L2 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l2: Option<f64>,
/// *(2.1)* Charging rate limit on phase L3 in the applicable _chargingRateUnit_.
#[cfg_attr(feature = "serde", serde(rename = "limit_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub limit_l3: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow as close as possible. Use negative values for discharging. +
/// When a limit and/or _dischargeLimit_ are given the overshoot when following _setpoint_ must remain within these values.
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow as closely as possible. Positive values for inductive, negative for capacitive reactive power or current. +
/// This field represents the sum of all phases, unless values are provided for L2 and L3, in which case this field represents phase L1.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L2 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l2: Option<f64>,
/// *(2.1)* Setpoint for reactive power (or current) in _chargingRateUnit_ that the EV should follow on phase L3 as closely as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpointReactive_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_reactive_l3: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L2 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L2"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l2: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L3 as close as possible.
#[cfg_attr(feature = "serde", serde(rename = "setpoint_L3"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub setpoint_l3: Option<f64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate
for ChargingScheduleUpdate<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.discharge_limit {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit"))?;
}
if let Some(value) = self.discharge_limit_l2 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L2"))?;
}
if let Some(value) = self.discharge_limit_l3 {
crate::validate::check_max_f64(value, 0f64)
.map_err(|error| error.in_field("dischargeLimit_L3"))?;
}
Ok(())
}
}
/// Result of request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChargingProfileStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChargingProfileStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates the kind of schedule.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChargingProfileKindEnum {
Absolute,
Recurring,
Relative,
Dynamic,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChargingProfileKindEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates the start point of a recurrence.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RecurrencyKindEnum {
Daily,
Weekly,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for RecurrencyKindEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// A ChargingProfile consists of 1 to 3 ChargingSchedules with a list of ChargingSchedulePeriods, describing the amount of power or current that can be delivered per time interval.
///
/// image::images/ChargingProfile-Simple.png\[\]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingProfile<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingProfileKind"))]
pub charging_profile_kind: ChargingProfileKindEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingProfilePurpose"))]
pub charging_profile_purpose: ChargingProfilePurposeEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedule"))]
pub charging_schedule: heapless::Vec<ChargingSchedule<CustomDataType>, 3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Interval in seconds after receipt of last update, when to request a profile update by sending a PullDynamicScheduleUpdateRequest message.
/// A value of 0 or no value means that no update interval applies. +
/// Only relevant in a dynamic charging profile.
#[cfg_attr(feature = "serde", serde(rename = "dynUpdateInterval"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dyn_update_interval: Option<i64>,
/// *(2.1)* Time at which limits or setpoints in this charging profile were last updated by a PullDynamicScheduleUpdateRequest or UpdateDynamicScheduleRequest or by an external actor. +
/// Only relevant in a dynamic charging profile.
#[cfg_attr(feature = "serde", serde(rename = "dynUpdateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dyn_update_time: Option<crate::OcppTimestamp>,
/// Id of ChargingProfile. Unique within charging station. Id can have a negative value. This is useful to distinguish charging profiles from an external actor (external constraints) from charging profiles received from CSMS.
pub id: i64,
/// *(2.1)* When set to true this charging profile will not be valid anymore after being offline for more than _maxOfflineDuration_. +
/// When absent defaults to false.
#[cfg_attr(feature = "serde", serde(rename = "invalidAfterOfflineDuration"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub invalid_after_offline_duration: Option<bool>,
/// *(2.1)* Period in seconds that this charging profile remains valid after the Charging Station has gone offline. After this period the charging profile becomes invalid for as long as it is offline and the Charging Station reverts back to a valid profile with a lower stack level.
/// If _invalidAfterOfflineDuration_ is true, then this charging profile will become permanently invalid.
/// A value of 0 means that the charging profile is immediately invalid while offline. When the field is absent, then no timeout applies and the charging profile remains valid when offline.
#[cfg_attr(feature = "serde", serde(rename = "maxOfflineDuration"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_offline_duration: Option<i64>,
/// *(2.1)* ISO 15118-20 signature for all price schedules in _chargingSchedules_. +
/// Note: for 256-bit elliptic curves (like secp256k1) the ECDSA signature is 512 bits (64 bytes) and for 521-bit curves (like secp521r1) the signature is 1042 bits. This equals 131 bytes, which can be encoded as base64 in 176 bytes.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleSignature"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_signature: Option<heapless::String<256usize>>,
#[cfg_attr(feature = "serde", serde(rename = "recurrencyKind"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub recurrency_kind: Option<RecurrencyKindEnum>,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[cfg_attr(feature = "serde", serde(rename = "stackLevel"))]
pub stack_level: i64,
/// SHALL only be included if ChargingProfilePurpose is set to TxProfile in a SetChargingProfileRequest. The transactionId is used to match the profile to a specific transaction.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
/// Point in time at which the profile starts to be valid. If absent, the profile is valid as soon as it is received by the Charging Station.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
/// Point in time at which the profile stops to be valid. If absent, the profile is valid until it is replaced by another profile.
#[cfg_attr(feature = "serde", serde(rename = "validTo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_to: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ChargingProfile<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.charging_profile_kind)
.map_err(|error| error.in_field("chargingProfileKind"))?;
crate::validate::Validate::validate(&self.charging_profile_purpose)
.map_err(|error| error.in_field("chargingProfilePurpose"))?;
crate::validate::check_min_items(self.charging_schedule.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedule"))?;
for (index, item) in self.charging_schedule.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("chargingSchedule"))?;
}
if let Some(value) = &self.recurrency_kind {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("recurrencyKind"))?;
}
crate::validate::check_min_i64(self.stack_level, 0i64)
.map_err(|error| error.in_field("stackLevel"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// A ChargingProfile consists of 1 to 3 ChargingSchedules with a list of ChargingSchedulePeriods, describing the amount of power or current that can be delivered per time interval.
///
/// image::images/ChargingProfile-Simple.png\[\]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingProfile<
CustomDataType = crate::NoCustomData,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize = 1024usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize = 8usize,
const CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize = 8usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize = 8usize,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize = 8usize,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "chargingProfileKind"))]
pub charging_profile_kind: ChargingProfileKindEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingProfilePurpose"))]
pub charging_profile_purpose: ChargingProfilePurposeEnum,
#[cfg_attr(feature = "serde", serde(rename = "chargingSchedule"))]
pub charging_schedule: heapless::Vec<
ChargingSchedule<
CustomDataType,
ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
SALES_TARIFF_SALES_TARIFF_ENTRY_CAP,
>,
3usize,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Interval in seconds after receipt of last update, when to request a profile update by sending a PullDynamicScheduleUpdateRequest message.
/// A value of 0 or no value means that no update interval applies. +
/// Only relevant in a dynamic charging profile.
#[cfg_attr(feature = "serde", serde(rename = "dynUpdateInterval"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dyn_update_interval: Option<i64>,
/// *(2.1)* Time at which limits or setpoints in this charging profile were last updated by a PullDynamicScheduleUpdateRequest or UpdateDynamicScheduleRequest or by an external actor. +
/// Only relevant in a dynamic charging profile.
#[cfg_attr(feature = "serde", serde(rename = "dynUpdateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dyn_update_time: Option<crate::OcppTimestamp>,
/// Id of ChargingProfile. Unique within charging station. Id can have a negative value. This is useful to distinguish charging profiles from an external actor (external constraints) from charging profiles received from CSMS.
pub id: i64,
/// *(2.1)* When set to true this charging profile will not be valid anymore after being offline for more than _maxOfflineDuration_. +
/// When absent defaults to false.
#[cfg_attr(feature = "serde", serde(rename = "invalidAfterOfflineDuration"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub invalid_after_offline_duration: Option<bool>,
/// *(2.1)* Period in seconds that this charging profile remains valid after the Charging Station has gone offline. After this period the charging profile becomes invalid for as long as it is offline and the Charging Station reverts back to a valid profile with a lower stack level.
/// If _invalidAfterOfflineDuration_ is true, then this charging profile will become permanently invalid.
/// A value of 0 means that the charging profile is immediately invalid while offline. When the field is absent, then no timeout applies and the charging profile remains valid when offline.
#[cfg_attr(feature = "serde", serde(rename = "maxOfflineDuration"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_offline_duration: Option<i64>,
/// *(2.1)* ISO 15118-20 signature for all price schedules in _chargingSchedules_. +
/// Note: for 256-bit elliptic curves (like secp256k1) the ECDSA signature is 512 bits (64 bytes) and for 521-bit curves (like secp521r1) the signature is 1042 bits. This equals 131 bytes, which can be encoded as base64 in 176 bytes.
#[cfg_attr(feature = "serde", serde(rename = "priceScheduleSignature"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub price_schedule_signature: Option<heapless::String<256usize>>,
#[cfg_attr(feature = "serde", serde(rename = "recurrencyKind"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub recurrency_kind: Option<RecurrencyKindEnum>,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[cfg_attr(feature = "serde", serde(rename = "stackLevel"))]
pub stack_level: i64,
/// SHALL only be included if ChargingProfilePurpose is set to TxProfile in a SetChargingProfileRequest. The transactionId is used to match the profile to a specific transaction.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_id: Option<heapless::String<36usize>>,
/// Point in time at which the profile starts to be valid. If absent, the profile is valid as soon as it is received by the Charging Station.
#[cfg_attr(feature = "serde", serde(rename = "validFrom"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_from: Option<crate::OcppTimestamp>,
/// Point in time at which the profile stops to be valid. If absent, the profile is valid until it is replaced by another profile.
#[cfg_attr(feature = "serde", serde(rename = "validTo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub valid_to: Option<crate::OcppTimestamp>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP: usize,
const ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP: usize,
const CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP: usize,
const CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP: usize,
const PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP: usize,
const SALES_TARIFF_SALES_TARIFF_ENTRY_CAP: usize,
> crate::validate::Validate
for ChargingProfile<
CustomDataType,
ABSOLUTE_PRICE_SCHEDULE_PRICE_ALGORITHM_CAP,
ABSOLUTE_PRICE_SCHEDULE_PRICE_RULE_STACKS_CAP,
CHARGING_SCHEDULE_CHARGING_SCHEDULE_PERIOD_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_FREQ_WATT_CURVE_CAP,
CHARGING_SCHEDULE_PERIOD_V2X_SIGNAL_WATT_CURVE_CAP,
PRICE_LEVEL_SCHEDULE_PRICE_LEVEL_SCHEDULE_ENTRIES_CAP,
SALES_TARIFF_SALES_TARIFF_ENTRY_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.charging_profile_kind)
.map_err(|error| error.in_field("chargingProfileKind"))?;
crate::validate::Validate::validate(&self.charging_profile_purpose)
.map_err(|error| error.in_field("chargingProfilePurpose"))?;
crate::validate::check_min_items(self.charging_schedule.len(), 1usize)
.map_err(|error| error.in_field("chargingSchedule"))?;
for (index, item) in self.charging_schedule.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("chargingSchedule"))?;
}
if let Some(value) = &self.recurrency_kind {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("recurrencyKind"))?;
}
crate::validate::check_min_i64(self.stack_level, 0i64)
.map_err(|error| error.in_field("stackLevel"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DERCurvePoints<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// The data value of the X-axis (independent) variable, depending on the curve type.
pub x: f64,
/// The data value of the Y-axis (dependent) variable, depending on the <<cmn_derunitenumtype>> of the curve. If _y_ is power factor, then a positive value means DER is absorbing reactive power (under-excited), a negative value when DER is injecting reactive power (over-excited).
pub y: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for DERCurvePoints<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Hysteresis<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Delay in seconds, once grid parameter within HysteresisLow and HysteresisHigh, for the EV to return to normal operation after a grid event.
#[cfg_attr(feature = "serde", serde(rename = "hysteresisDelay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hysteresis_delay: Option<f64>,
/// Set default rate of change (ramp rate %/s) for the EV to return to normal operation after a grid event
#[cfg_attr(feature = "serde", serde(rename = "hysteresisGradient"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hysteresis_gradient: Option<f64>,
/// High value for return to normal operation after a grid event, in absolute value. This value adopts the same unit as defined by yUnit
#[cfg_attr(feature = "serde", serde(rename = "hysteresisHigh"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hysteresis_high: Option<f64>,
/// Low value for return to normal operation after a grid event, in absolute value. This value adopts the same unit as defined by yUnit
#[cfg_attr(feature = "serde", serde(rename = "hysteresisLow"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hysteresis_low: Option<f64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Hysteresis<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ReactivePowerParams<CustomDataType = crate::NoCustomData> {
/// Only for VoltVar: Enable/disable autonomous VRef adjustment
#[cfg_attr(feature = "serde", serde(rename = "autonomousVRefEnable"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub autonomous_v_ref_enable: Option<bool>,
/// Only for VoltVar: Adjustment range for VRef time constant
#[cfg_attr(feature = "serde", serde(rename = "autonomousVRefTimeConstant"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub autonomous_v_ref_time_constant: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Only for VoltVar curve: The nominal ac voltage (rms) adjustment to the voltage curve points for Volt-Var curves (percentage).
#[cfg_attr(feature = "serde", serde(rename = "vRef"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub v_ref: Option<f64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for ReactivePowerParams<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Parameter is only sent, if the EV has to feed-in power or reactive power during fault-ride through (FRT) as defined by HVMomCess curve and LVMomCess curve.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PowerDuringCessationEnum {
Active,
Reactive,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PowerDuringCessationEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VoltageParams<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Time for which the voltage is allowed to stay above the 10 min mean value.
/// After this time, the EV must trip.
/// This value is mandatory if OverVoltageMeanValue10min is set.
#[cfg_attr(feature = "serde", serde(rename = "hv10MinMeanTripDelay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hv10_min_mean_trip_delay: Option<f64>,
/// EN 50549-1 chapter 4.9.3.4
/// Voltage threshold for the 10 min time window mean value monitoring.
/// The 10 min mean is recalculated up to every 3 s.
/// If the present voltage is above this threshold for more than the time defined by _hv10MinMeanValue_, the EV must trip.
/// This value is mandatory if _hv10MinMeanTripDelay_ is set.
#[cfg_attr(feature = "serde", serde(rename = "hv10MinMeanValue"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hv10_min_mean_value: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "powerDuringCessation"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub power_during_cessation: Option<PowerDuringCessationEnum>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for VoltageParams<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.power_during_cessation {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("powerDuringCessation"))?;
}
Ok(())
}
}
/// Unit of the Y-axis of DER curve
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DERUnitEnum {
#[cfg_attr(feature = "serde", serde(rename = "Not_Applicable"))]
NotApplicable,
PctMaxW,
PctMaxVar,
PctWAvail,
PctVarAvail,
PctEffectiveV,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DERUnitEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DERCurve<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "curveData"))]
pub curve_data: heapless::Vec<DERCurvePoints<CustomDataType>, 10usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration in seconds that this curve will be active. Only absent when _default_ is true.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<f64>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub hysteresis: Option<Hysteresis<CustomDataType>>,
/// Priority of curve (0=highest)
pub priority: i64,
#[cfg_attr(feature = "serde", serde(rename = "reactivePowerParams"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reactive_power_params: Option<ReactivePowerParams<CustomDataType>>,
/// Open loop response time, the time to ramp up to 90% of the new target in response to the change in voltage, in seconds. A value of 0 is used to mean no limit. When not present, the device should follow its default behavior.
#[cfg_attr(feature = "serde", serde(rename = "responseTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub response_time: Option<f64>,
/// Point in time when this curve will become activated. Only absent when _default_ is true.
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time: Option<crate::OcppTimestamp>,
#[cfg_attr(feature = "serde", serde(rename = "voltageParams"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub voltage_params: Option<VoltageParams<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "yUnit"))]
pub y_unit: DERUnitEnum,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for DERCurve<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_items(self.curve_data.len(), 1usize)
.map_err(|error| error.in_field("curveData"))?;
for (index, item) in self.curve_data.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("curveData"))?;
}
if let Some(value) = &self.hysteresis {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("hysteresis"))?;
}
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
if let Some(value) = &self.reactive_power_params {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reactivePowerParams"))?;
}
if let Some(value) = &self.voltage_params {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("voltageParams"))?;
}
crate::validate::Validate::validate(&self.y_unit)
.map_err(|error| error.in_field("yUnit"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DERCurveGet<CustomDataType = crate::NoCustomData> {
pub curve: DERCurve<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "curveType"))]
pub curve_type: DERControlEnum,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id of DER curve
pub id: heapless::String<36usize>,
/// True if this is a default curve
#[cfg_attr(feature = "serde", serde(rename = "isDefault"))]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[cfg_attr(feature = "serde", serde(rename = "isSuperseded"))]
pub is_superseded: bool,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for DERCurveGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.curve)
.map_err(|error| error.in_field("curve"))?;
crate::validate::Validate::validate(&self.curve_type)
.map_err(|error| error.in_field("curveType"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EnterService<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Enter service delay
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub delay: Option<f64>,
/// Enter service frequency high
#[cfg_attr(feature = "serde", serde(rename = "highFreq"))]
pub high_freq: f64,
/// Enter service voltage high
#[cfg_attr(feature = "serde", serde(rename = "highVoltage"))]
pub high_voltage: f64,
/// Enter service frequency low
#[cfg_attr(feature = "serde", serde(rename = "lowFreq"))]
pub low_freq: f64,
/// Enter service voltage low
#[cfg_attr(feature = "serde", serde(rename = "lowVoltage"))]
pub low_voltage: f64,
/// Priority of setting (0=highest)
pub priority: i64,
/// Enter service ramp rate in seconds
#[cfg_attr(feature = "serde", serde(rename = "rampRate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ramp_rate: Option<f64>,
/// Enter service randomized delay
#[cfg_attr(feature = "serde", serde(rename = "randomDelay"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub random_delay: Option<f64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for EnterService<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EnterServiceGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "enterService"))]
pub enter_service: EnterService<CustomDataType>,
/// Id of setting
pub id: heapless::String<36usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for EnterServiceGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.enter_service)
.map_err(|error| error.in_field("enterService"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedPF<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Power factor, cos(phi), as value between 0..1.
pub displacement: f64,
/// Duration in seconds that this setting is active.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<f64>,
/// True when absorbing reactive power (under-excited), false when injecting reactive power (over-excited).
pub excitation: bool,
/// Priority of setting (0=highest)
pub priority: i64,
/// Time when this setting becomes active
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time: Option<crate::OcppTimestamp>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FixedPF<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedPFGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "fixedPF"))]
pub fixed_p_f: FixedPF<CustomDataType>,
/// Id of setting.
pub id: heapless::String<36usize>,
/// True if setting is a default control.
#[cfg_attr(feature = "serde", serde(rename = "isDefault"))]
pub is_default: bool,
/// True if this setting is superseded by a lower priority setting.
#[cfg_attr(feature = "serde", serde(rename = "isSuperseded"))]
pub is_superseded: bool,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FixedPFGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.fixed_p_f)
.map_err(|error| error.in_field("fixedPF"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedVar<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration in seconds that this setting is active.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<f64>,
/// Priority of setting (0=highest)
pub priority: i64,
/// The value specifies a target var output interpreted as a signed percentage (-100 to 100).
/// A negative value refers to charging, whereas a positive one refers to discharging.
/// The value type is determined by the unit field.
pub setpoint: f64,
/// Time when this setting becomes active.
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time: Option<crate::OcppTimestamp>,
pub unit: DERUnitEnum,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FixedVar<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
crate::validate::Validate::validate(&self.unit)
.map_err(|error| error.in_field("unit"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedVarGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "fixedVar"))]
pub fixed_var: FixedVar<CustomDataType>,
/// Id of setting
pub id: heapless::String<36usize>,
/// True if setting is a default control.
#[cfg_attr(feature = "serde", serde(rename = "isDefault"))]
pub is_default: bool,
/// True if this setting is superseded by a lower priority setting
#[cfg_attr(feature = "serde", serde(rename = "isSuperseded"))]
pub is_superseded: bool,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FixedVarGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.fixed_var)
.map_err(|error| error.in_field("fixedVar"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FreqDroop<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration in seconds that this setting is active
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<f64>,
/// Over-frequency droop per unit, oFDroop
#[cfg_attr(feature = "serde", serde(rename = "overDroop"))]
pub over_droop: f64,
/// Over-frequency start of droop
#[cfg_attr(feature = "serde", serde(rename = "overFreq"))]
pub over_freq: f64,
/// Priority of setting (0=highest)
pub priority: i64,
/// Open loop response time in seconds
#[cfg_attr(feature = "serde", serde(rename = "responseTime"))]
pub response_time: f64,
/// Time when this setting becomes active
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time: Option<crate::OcppTimestamp>,
/// Under-frequency droop per unit, uFDroop
#[cfg_attr(feature = "serde", serde(rename = "underDroop"))]
pub under_droop: f64,
/// Under-frequency start of droop
#[cfg_attr(feature = "serde", serde(rename = "underFreq"))]
pub under_freq: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FreqDroop<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FreqDroopGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "freqDroop"))]
pub freq_droop: FreqDroop<CustomDataType>,
/// Id of setting
pub id: heapless::String<36usize>,
/// True if setting is a default control.
#[cfg_attr(feature = "serde", serde(rename = "isDefault"))]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[cfg_attr(feature = "serde", serde(rename = "isSuperseded"))]
pub is_superseded: bool,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for FreqDroopGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.freq_droop)
.map_err(|error| error.in_field("freqDroop"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Gradient<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Default ramp rate in seconds (0 if not applicable)
pub gradient: f64,
/// Id of setting
pub priority: i64,
/// Soft-start ramp rate in seconds (0 if not applicable)
#[cfg_attr(feature = "serde", serde(rename = "softGradient"))]
pub soft_gradient: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Gradient<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GradientGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub gradient: Gradient<CustomDataType>,
/// Id of setting
pub id: heapless::String<36usize>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for GradientGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.gradient)
.map_err(|error| error.in_field("gradient"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LimitMaxDischarge<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Duration in seconds that this setting is active
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duration: Option<f64>,
/// Only for PowerMonitoring. +
/// The value specifies a percentage (0 to 100) of the rated maximum discharge power of EV.
/// The PowerMonitoring curve becomes active when power exceeds this percentage.
#[cfg_attr(feature = "serde", serde(rename = "pctMaxDischargePower"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub pct_max_discharge_power: Option<f64>,
#[cfg_attr(feature = "serde", serde(rename = "powerMonitoringMustTrip"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub power_monitoring_must_trip: Option<DERCurve<CustomDataType>>,
/// Priority of setting (0=highest)
pub priority: i64,
/// Time when this setting becomes active
#[cfg_attr(feature = "serde", serde(rename = "startTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub start_time: Option<crate::OcppTimestamp>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for LimitMaxDischarge<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.power_monitoring_must_trip {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("powerMonitoringMustTrip"))?;
}
crate::validate::check_min_i64(self.priority, 0i64)
.map_err(|error| error.in_field("priority"))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LimitMaxDischargeGet<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id of setting
pub id: heapless::String<36usize>,
/// True if setting is a default control.
#[cfg_attr(feature = "serde", serde(rename = "isDefault"))]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[cfg_attr(feature = "serde", serde(rename = "isSuperseded"))]
pub is_superseded: bool,
#[cfg_attr(feature = "serde", serde(rename = "limitMaxDischarge"))]
pub limit_max_discharge: LimitMaxDischarge<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for LimitMaxDischargeGet<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.limit_max_discharge)
.map_err(|error| error.in_field("limitMaxDischarge"))?;
Ok(())
}
}
/// Status indicating whether the Charging Station accepts the request to start a transaction.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RequestStartStopStatusEnum {
Accepted,
Rejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for RequestStartStopStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// The updated reservation status.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReservationUpdateStatusEnum {
Expired,
Removed,
NoTransaction,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ReservationUpdateStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates the success or failure of the reservation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReserveNowStatusEnum {
Accepted,
Faulted,
Occupied,
Rejected,
Unavailable,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ReserveNowStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains the type of reset that the Charging Station or EVSE should perform.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ResetEnum {
Immediate,
OnIdle,
ImmediateAndResume,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ResetEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station is able to perform the reset.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ResetStatusEnum {
Accepted,
Rejected,
Scheduled,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ResetStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Contains the identifier to use for authorization.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AuthorizationData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "idToken"))]
pub id_token: IdToken<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "idTokenInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id_token_info: Option<IdTokenInfo<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for AuthorizationData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.id_token)
.map_err(|error| error.in_field("idToken"))?;
if let Some(value) = &self.id_token_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("idTokenInfo"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Contains the identifier to use for authorization.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AuthorizationData<
CustomDataType = crate::NoCustomData,
const ID_TOKEN_ADDITIONAL_INFO_CAP: usize = 8usize,
const ID_TOKEN_INFO_EVSE_ID_CAP: usize = 8usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "idToken"))]
pub id_token: IdToken<CustomDataType, ID_TOKEN_ADDITIONAL_INFO_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "idTokenInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id_token_info: Option<
IdTokenInfo<
CustomDataType,
ID_TOKEN_INFO_EVSE_ID_CAP,
ID_TOKEN_ADDITIONAL_INFO_CAP,
MESSAGE_CONTENT_CONTENT_CAP,
>,
>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const ID_TOKEN_ADDITIONAL_INFO_CAP: usize,
const ID_TOKEN_INFO_EVSE_ID_CAP: usize,
const MESSAGE_CONTENT_CONTENT_CAP: usize,
> crate::validate::Validate
for AuthorizationData<
CustomDataType,
ID_TOKEN_ADDITIONAL_INFO_CAP,
ID_TOKEN_INFO_EVSE_ID_CAP,
MESSAGE_CONTENT_CONTENT_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.id_token)
.map_err(|error| error.in_field("idToken"))?;
if let Some(value) = &self.id_token_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("idTokenInfo"))?;
}
Ok(())
}
}
/// This contains the type of update (full or differential) of this request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum UpdateEnum {
Differential,
Full,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for UpdateEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station has successfully received and applied the update of the Local Authorization List.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SendLocalListStatusEnum {
Accepted,
Failed,
VersionMismatch,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for SendLocalListStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffSetStatusEnum {
Accepted,
Rejected,
TooManyElements,
ConditionNotSupported,
DuplicateTariffId,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffSetStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station is able to display the message.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DisplayMessageStatusEnum {
Accepted,
NotSupportedMessageFormat,
Rejected,
NotSupportedPriority,
NotSupportedState,
UnknownTransaction,
LanguageNotSupported,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for DisplayMessageStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Specify which monitoring base will be set
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MonitoringBaseEnum {
All,
FactoryDefault,
HardWiredOnly,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MonitoringBaseEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Authentication method.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum APNAuthenticationEnum {
PAP,
CHAP,
NONE,
AUTO,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for APNAuthenticationEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Collection of configuration data needed to make a data-connection over a cellular network.
///
/// NOTE: When asking a GSM modem to dial in, it is possible to specify which mobile operator should be used. This can be done with the mobile country code (MCC) in combination with a mobile network code (MNC). Example: If your preferred network is Vodafone Netherlands, the MCC=204 and the MNC=04 which means the key PreferredNetwork = 20404 Some modems allows to specify a preferred network, which means, if this network is not available, a different network is used. If you specify UseOnlyPreferredNetwork and this network is not available, the modem will not dial in.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct APN<CustomDataType = crate::NoCustomData> {
/// The Access Point Name as an URL.
pub apn: alloc::string::String,
#[cfg_attr(feature = "serde", serde(rename = "apnAuthentication"))]
pub apn_authentication: APNAuthenticationEnum,
/// *(2.1)* APN Password.
#[cfg_attr(feature = "serde", serde(rename = "apnPassword"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn_password: Option<heapless::String<64usize>>,
/// APN username.
#[cfg_attr(feature = "serde", serde(rename = "apnUserName"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn_user_name: Option<heapless::String<50usize>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Preferred network, written as MCC and MNC concatenated. See note.
#[cfg_attr(feature = "serde", serde(rename = "preferredNetwork"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub preferred_network: Option<heapless::String<6usize>>,
/// SIM card pin code.
#[cfg_attr(feature = "serde", serde(rename = "simPin"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sim_pin: Option<i64>,
/// Default: false. Use only the preferred Network, do
/// not dial in when not available. See Note.
#[cfg_attr(feature = "serde", serde(rename = "useOnlyPreferredNetwork"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub use_only_preferred_network: Option<bool>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for APN<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.apn, 2000usize)
.map_err(|error| error.in_field("apn"))?;
crate::validate::Validate::validate(&self.apn_authentication)
.map_err(|error| error.in_field("apnAuthentication"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Collection of configuration data needed to make a data-connection over a cellular network.
///
/// NOTE: When asking a GSM modem to dial in, it is possible to specify which mobile operator should be used. This can be done with the mobile country code (MCC) in combination with a mobile network code (MNC). Example: If your preferred network is Vodafone Netherlands, the MCC=204 and the MNC=04 which means the key PreferredNetwork = 20404 Some modems allows to specify a preferred network, which means, if this network is not available, a different network is used. If you specify UseOnlyPreferredNetwork and this network is not available, the modem will not dial in.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct APN<
CustomDataType = crate::NoCustomData,
const A_P_N_APN_CAP: usize = 1024usize,
> {
/// The Access Point Name as an URL.
pub apn: heapless::String<A_P_N_APN_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "apnAuthentication"))]
pub apn_authentication: APNAuthenticationEnum,
/// *(2.1)* APN Password.
#[cfg_attr(feature = "serde", serde(rename = "apnPassword"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn_password: Option<heapless::String<64usize>>,
/// APN username.
#[cfg_attr(feature = "serde", serde(rename = "apnUserName"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn_user_name: Option<heapless::String<50usize>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Preferred network, written as MCC and MNC concatenated. See note.
#[cfg_attr(feature = "serde", serde(rename = "preferredNetwork"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub preferred_network: Option<heapless::String<6usize>>,
/// SIM card pin code.
#[cfg_attr(feature = "serde", serde(rename = "simPin"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub sim_pin: Option<i64>,
/// Default: false. Use only the preferred Network, do
/// not dial in when not available. See Note.
#[cfg_attr(feature = "serde", serde(rename = "useOnlyPreferredNetwork"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub use_only_preferred_network: Option<bool>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const A_P_N_APN_CAP: usize> crate::validate::Validate
for APN<CustomDataType, A_P_N_APN_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.apn, 2000usize)
.map_err(|error| error.in_field("apn"))?;
crate::validate::Validate::validate(&self.apn_authentication)
.map_err(|error| error.in_field("apnAuthentication"))?;
Ok(())
}
}
/// Applicable Network Interface. Charging Station is allowed to use a different network interface to connect if the given one does not work.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OCPPInterfaceEnum {
Wired0,
Wired1,
Wired2,
Wired3,
Wireless0,
Wireless1,
Wireless2,
Wireless3,
Any,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for OCPPInterfaceEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Defines the transport protocol (e.g. SOAP or JSON). Note: SOAP is not supported in OCPP 2.x, but is supported by earlier versions of OCPP.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OCPPTransportEnum {
SOAP,
JSON,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for OCPPTransportEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* This field is ignored, since the OCPP version to use is determined during the websocket handshake. The field is only kept for backwards compatibility with the OCPP 2.0.1 JSON schema.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OCPPVersionEnum {
OCPP12,
OCPP15,
OCPP16,
OCPP20,
OCPP201,
OCPP21,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for OCPPVersionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of VPN
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum VPNEnum {
IKEv2,
IPSec,
L2TP,
PPTP,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for VPNEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// VPN Configuration settings
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VPN<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// VPN group.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub group: Option<heapless::String<50usize>>,
/// VPN shared secret.
pub key: heapless::String<255usize>,
/// *(2.1)* VPN Password.
pub password: heapless::String<64usize>,
/// VPN Server Address
pub server: alloc::string::String,
pub r#type: VPNEnum,
/// VPN User
pub user: heapless::String<50usize>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for VPN<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.server, 2000usize)
.map_err(|error| error.in_field("server"))?;
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// VPN Configuration settings
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VPN<
CustomDataType = crate::NoCustomData,
const V_P_N_SERVER_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// VPN group.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub group: Option<heapless::String<50usize>>,
/// VPN shared secret.
pub key: heapless::String<255usize>,
/// *(2.1)* VPN Password.
pub password: heapless::String<64usize>,
/// VPN Server Address
pub server: heapless::String<V_P_N_SERVER_CAP>,
pub r#type: VPNEnum,
/// VPN User
pub user: heapless::String<50usize>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<CustomDataType, const V_P_N_SERVER_CAP: usize> crate::validate::Validate
for VPN<CustomDataType, V_P_N_SERVER_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.server, 2000usize)
.map_err(|error| error.in_field("server"))?;
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// The NetworkConnectionProfile defines the functional and technical parameters of a communication link.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NetworkConnectionProfile<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn: Option<APN<CustomDataType>>,
/// *(2.1)* BasicAuthPassword to use for security profile 1 or 2.
#[cfg_attr(feature = "serde", serde(rename = "basicAuthPassword"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub basic_auth_password: Option<heapless::String<64usize>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Charging Station identity to be used as the basic authentication username.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub identity: Option<heapless::String<48usize>>,
/// Duration in seconds before a message send by the Charging Station via this network connection times-out.
/// The best setting depends on the underlying network and response times of the CSMS.
/// If you are looking for a some guideline: use 30 seconds as a starting point.
#[cfg_attr(feature = "serde", serde(rename = "messageTimeout"))]
pub message_timeout: i64,
/// URL of the CSMS(s) that this Charging Station communicates with, without the Charging Station identity part. +
/// The SecurityCtrlr.Identity field is appended to _ocppCsmsUrl_ to provide the full websocket URL.
#[cfg_attr(feature = "serde", serde(rename = "ocppCsmsUrl"))]
pub ocpp_csms_url: alloc::string::String,
#[cfg_attr(feature = "serde", serde(rename = "ocppInterface"))]
pub ocpp_interface: OCPPInterfaceEnum,
#[cfg_attr(feature = "serde", serde(rename = "ocppTransport"))]
pub ocpp_transport: OCPPTransportEnum,
#[cfg_attr(feature = "serde", serde(rename = "ocppVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ocpp_version: Option<OCPPVersionEnum>,
/// This field specifies the security profile used when connecting to the CSMS with this NetworkConnectionProfile.
#[cfg_attr(feature = "serde", serde(rename = "securityProfile"))]
pub security_profile: i64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub vpn: Option<VPN<CustomDataType>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate
for NetworkConnectionProfile<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.apn {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("apn"))?;
}
crate::validate::check_max_length(&self.ocpp_csms_url, 2000usize)
.map_err(|error| error.in_field("ocppCsmsUrl"))?;
crate::validate::Validate::validate(&self.ocpp_interface)
.map_err(|error| error.in_field("ocppInterface"))?;
crate::validate::Validate::validate(&self.ocpp_transport)
.map_err(|error| error.in_field("ocppTransport"))?;
if let Some(value) = &self.ocpp_version {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("ocppVersion"))?;
}
crate::validate::check_min_i64(self.security_profile, 0i64)
.map_err(|error| error.in_field("securityProfile"))?;
if let Some(value) = &self.vpn {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("vpn"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// The NetworkConnectionProfile defines the functional and technical parameters of a communication link.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NetworkConnectionProfile<
CustomDataType = crate::NoCustomData,
const A_P_N_APN_CAP: usize = 1024usize,
const NETWORK_CONNECTION_PROFILE_OCPP_CSMS_URL_CAP: usize = 1024usize,
const V_P_N_SERVER_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub apn: Option<APN<CustomDataType, A_P_N_APN_CAP>>,
/// *(2.1)* BasicAuthPassword to use for security profile 1 or 2.
#[cfg_attr(feature = "serde", serde(rename = "basicAuthPassword"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub basic_auth_password: Option<heapless::String<64usize>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// *(2.1)* Charging Station identity to be used as the basic authentication username.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub identity: Option<heapless::String<48usize>>,
/// Duration in seconds before a message send by the Charging Station via this network connection times-out.
/// The best setting depends on the underlying network and response times of the CSMS.
/// If you are looking for a some guideline: use 30 seconds as a starting point.
#[cfg_attr(feature = "serde", serde(rename = "messageTimeout"))]
pub message_timeout: i64,
/// URL of the CSMS(s) that this Charging Station communicates with, without the Charging Station identity part. +
/// The SecurityCtrlr.Identity field is appended to _ocppCsmsUrl_ to provide the full websocket URL.
#[cfg_attr(feature = "serde", serde(rename = "ocppCsmsUrl"))]
pub ocpp_csms_url: heapless::String<NETWORK_CONNECTION_PROFILE_OCPP_CSMS_URL_CAP>,
#[cfg_attr(feature = "serde", serde(rename = "ocppInterface"))]
pub ocpp_interface: OCPPInterfaceEnum,
#[cfg_attr(feature = "serde", serde(rename = "ocppTransport"))]
pub ocpp_transport: OCPPTransportEnum,
#[cfg_attr(feature = "serde", serde(rename = "ocppVersion"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub ocpp_version: Option<OCPPVersionEnum>,
/// This field specifies the security profile used when connecting to the CSMS with this NetworkConnectionProfile.
#[cfg_attr(feature = "serde", serde(rename = "securityProfile"))]
pub security_profile: i64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub vpn: Option<VPN<CustomDataType, V_P_N_SERVER_CAP>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const A_P_N_APN_CAP: usize,
const NETWORK_CONNECTION_PROFILE_OCPP_CSMS_URL_CAP: usize,
const V_P_N_SERVER_CAP: usize,
> crate::validate::Validate
for NetworkConnectionProfile<
CustomDataType,
A_P_N_APN_CAP,
NETWORK_CONNECTION_PROFILE_OCPP_CSMS_URL_CAP,
V_P_N_SERVER_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.apn {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("apn"))?;
}
crate::validate::check_max_length(&self.ocpp_csms_url, 2000usize)
.map_err(|error| error.in_field("ocppCsmsUrl"))?;
crate::validate::Validate::validate(&self.ocpp_interface)
.map_err(|error| error.in_field("ocppInterface"))?;
crate::validate::Validate::validate(&self.ocpp_transport)
.map_err(|error| error.in_field("ocppTransport"))?;
if let Some(value) = &self.ocpp_version {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("ocppVersion"))?;
}
crate::validate::check_min_i64(self.security_profile, 0i64)
.map_err(|error| error.in_field("securityProfile"))?;
if let Some(value) = &self.vpn {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("vpn"))?;
}
Ok(())
}
}
/// Result of operation.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SetNetworkProfileStatusEnum {
Accepted,
Rejected,
Failed,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for SetNetworkProfileStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Class to hold parameters of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetMonitoringData<CustomDataType = crate::NoCustomData> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// An id SHALL only be given to replace an existing monitor. The Charging Station handles the generation of id's for new monitors.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "periodicEventStream"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub periodic_event_stream: Option<PeriodicEventStreamParams<CustomDataType>>,
/// The severity that will be assigned to an event that is triggered by this monitor. The severity range is 0-9, with 0 as the highest and 9 as the lowest severity level.
///
/// The severity levels have the following meaning: +
/// *0-Danger* +
/// Indicates lives are potentially in danger. Urgent attention is needed and action should be taken immediately. +
/// *1-Hardware Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to Hardware issues. Action is required. +
/// *2-System Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to software or minor hardware issues. Action is required. +
/// *3-Critical* +
/// Indicates a critical error. Action is required. +
/// *4-Error* +
/// Indicates a non-urgent error. Action is required. +
/// *5-Alert* +
/// Indicates an alert event. Default severity for any type of monitoring event. +
/// *6-Warning* +
/// Indicates a warning event. Action may be required. +
/// *7-Notice* +
/// Indicates an unusual event. No immediate action is required. +
/// *8-Informational* +
/// Indicates a regular operational event. May be used for reporting, measuring throughput, etc. No action is required. +
/// *9-Debug* +
/// Indicates information useful to developers for debugging, not useful during operations.
pub severity: i64,
/// Monitor only active when a transaction is ongoing on a component relevant to this transaction. Default = false.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction: Option<bool>,
pub r#type: MonitorEnum,
/// Value for threshold or delta monitoring.
/// For Periodic or PeriodicClockAligned this is the interval in seconds.
pub value: f64,
pub variable: Variable<CustomDataType>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for SetMonitoringData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
if let Some(value) = self.id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("id"))?;
}
if let Some(value) = &self.periodic_event_stream {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("periodicEventStream"))?;
}
crate::validate::check_min_i64(self.severity, 0i64)
.map_err(|error| error.in_field("severity"))?;
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
/// Status is OK if a value could be returned. Otherwise this will indicate the reason why a value could not be returned.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SetMonitoringStatusEnum {
Accepted,
UnknownComponent,
UnknownVariable,
UnsupportedMonitorType,
Rejected,
Duplicate,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for SetMonitoringStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Class to hold result of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetMonitoringResult<CustomDataType = crate::NoCustomData> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id given to the VariableMonitor by the Charging Station. The Id is only returned when status is accepted. Installed VariableMonitors should have unique id's but the id's of removed Installed monitors should have unique id's but the id's of removed monitors MAY be reused.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id: Option<i64>,
/// The severity that will be assigned to an event that is triggered by this monitor. The severity range is 0-9, with 0 as the highest and 9 as the lowest severity level.
///
/// The severity levels have the following meaning: +
/// *0-Danger* +
/// Indicates lives are potentially in danger. Urgent attention is needed and action should be taken immediately. +
/// *1-Hardware Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to Hardware issues. Action is required. +
/// *2-System Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to software or minor hardware issues. Action is required. +
/// *3-Critical* +
/// Indicates a critical error. Action is required. +
/// *4-Error* +
/// Indicates a non-urgent error. Action is required. +
/// *5-Alert* +
/// Indicates an alert event. Default severity for any type of monitoring event. +
/// *6-Warning* +
/// Indicates a warning event. Action may be required. +
/// *7-Notice* +
/// Indicates an unusual event. No immediate action is required. +
/// *8-Informational* +
/// Indicates a regular operational event. May be used for reporting, measuring throughput, etc. No action is required. +
/// *9-Debug* +
/// Indicates information useful to developers for debugging, not useful during operations.
pub severity: i64,
pub status: SetMonitoringStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType>>,
pub r#type: MonitorEnum,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SetMonitoringResult<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
if let Some(value) = self.id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("id"))?;
}
crate::validate::check_min_i64(self.severity, 0i64)
.map_err(|error| error.in_field("severity"))?;
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Class to hold result of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetMonitoringResult<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
> {
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Id given to the VariableMonitor by the Charging Station. The Id is only returned when status is accepted. Installed VariableMonitors should have unique id's but the id's of removed Installed monitors should have unique id's but the id's of removed monitors MAY be reused.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub id: Option<i64>,
/// The severity that will be assigned to an event that is triggered by this monitor. The severity range is 0-9, with 0 as the highest and 9 as the lowest severity level.
///
/// The severity levels have the following meaning: +
/// *0-Danger* +
/// Indicates lives are potentially in danger. Urgent attention is needed and action should be taken immediately. +
/// *1-Hardware Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to Hardware issues. Action is required. +
/// *2-System Failure* +
/// Indicates that the Charging Station is unable to continue regular operations due to software or minor hardware issues. Action is required. +
/// *3-Critical* +
/// Indicates a critical error. Action is required. +
/// *4-Error* +
/// Indicates a non-urgent error. Action is required. +
/// *5-Alert* +
/// Indicates an alert event. Default severity for any type of monitoring event. +
/// *6-Warning* +
/// Indicates a warning event. Action may be required. +
/// *7-Notice* +
/// Indicates an unusual event. No immediate action is required. +
/// *8-Informational* +
/// Indicates a regular operational event. May be used for reporting, measuring throughput, etc. No action is required. +
/// *9-Debug* +
/// Indicates information useful to developers for debugging, not useful during operations.
pub severity: i64,
pub status: SetMonitoringStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "statusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub status_info: Option<StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP>>,
pub r#type: MonitorEnum,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
> crate::validate::Validate
for SetMonitoringResult<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
if let Some(value) = self.id {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("id"))?;
}
crate::validate::check_min_i64(self.severity, 0i64)
.map_err(|error| error.in_field("severity"))?;
crate::validate::Validate::validate(&self.status)
.map_err(|error| error.in_field("status"))?;
if let Some(value) = &self.status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("statusInfo"))?;
}
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetVariableData<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
/// Value to be assigned to attribute of variable.
/// This value is allowed to be an empty string ("").
///
/// The Configuration Variable <<configkey-configuration-value-size,ConfigurationValueSize>> can be used to limit SetVariableData.attributeValue and VariableCharacteristics.valuesList. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "attributeValue"))]
pub attribute_value: alloc::string::String,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SetVariableData<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
crate::validate::check_max_length(&self.attribute_value, 2500usize)
.map_err(|error| error.in_field("attributeValue"))?;
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetVariableData<
CustomDataType = crate::NoCustomData,
const SET_VARIABLE_DATA_ATTRIBUTE_VALUE_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
/// Value to be assigned to attribute of variable.
/// This value is allowed to be an empty string ("").
///
/// The Configuration Variable <<configkey-configuration-value-size,ConfigurationValueSize>> can be used to limit SetVariableData.attributeValue and VariableCharacteristics.valuesList. The max size of these values will always remain equal.
#[cfg_attr(feature = "serde", serde(rename = "attributeValue"))]
pub attribute_value: heapless::String<SET_VARIABLE_DATA_ATTRIBUTE_VALUE_CAP>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const SET_VARIABLE_DATA_ATTRIBUTE_VALUE_CAP: usize,
> crate::validate::Validate
for SetVariableData<CustomDataType, SET_VARIABLE_DATA_ATTRIBUTE_VALUE_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
crate::validate::check_max_length(&self.attribute_value, 2500usize)
.map_err(|error| error.in_field("attributeValue"))?;
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
/// Result status of setting the variable.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SetVariableStatusEnum {
Accepted,
Rejected,
UnknownComponent,
UnknownVariable,
NotSupportedAttributeType,
RebootRequired,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for SetVariableStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetVariableResult<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "attributeStatus"))]
pub attribute_status: SetVariableStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "attributeStatusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_status_info: Option<StatusInfo<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for SetVariableResult<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.attribute_status)
.map_err(|error| error.in_field("attributeStatus"))?;
if let Some(value) = &self.attribute_status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeStatusInfo"))?;
}
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SetVariableResult<
CustomDataType = crate::NoCustomData,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "attributeStatus"))]
pub attribute_status: SetVariableStatusEnum,
#[cfg_attr(feature = "serde", serde(rename = "attributeStatusInfo"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_status_info: Option<
StatusInfo<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP>,
>,
#[cfg_attr(feature = "serde", serde(rename = "attributeType"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub attribute_type: Option<AttributeEnum>,
pub component: Component<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub variable: Variable<CustomDataType>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const STATUS_INFO_ADDITIONAL_INFO_CAP: usize,
> crate::validate::Validate
for SetVariableResult<CustomDataType, STATUS_INFO_ADDITIONAL_INFO_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.attribute_status)
.map_err(|error| error.in_field("attributeStatus"))?;
if let Some(value) = &self.attribute_status_info {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeStatusInfo"))?;
}
if let Some(value) = &self.attribute_type {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("attributeType"))?;
}
crate::validate::Validate::validate(&self.component)
.map_err(|error| error.in_field("component"))?;
crate::validate::Validate::validate(&self.variable)
.map_err(|error| error.in_field("variable"))?;
Ok(())
}
}
/// This contains the current status of the Connector.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ConnectorStatusEnum {
Available,
Occupied,
Reserved,
Unavailable,
Faulted,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ConnectorStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of cost dimension: energy, power, time, etc.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CostDimensionEnum {
Energy,
MaxCurrent,
MinCurrent,
MaxPower,
MinPower,
IdleTIme,
ChargingTime,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for CostDimensionEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Volume consumed of cost dimension.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CostDimension<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub r#type: CostDimensionEnum,
/// Volume of the dimension consumed, measured according to the dimension type.
pub volume: f64,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for CostDimension<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::Validate::validate(&self.r#type)
.map_err(|error| error.in_field("type"))?;
Ok(())
}
}
#[cfg(feature = "alloc")]
/// A ChargingPeriodType consists of a start time, and a list of possible values that influence this period, for example: amount of energy charged this period, maximum current during this period etc.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingPeriod<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dimensions: Option<alloc::vec::Vec<CostDimension<CustomDataType>>>,
/// Start timestamp of charging period. A period ends when the next period starts. The last period ends when the session ends.
#[cfg_attr(feature = "serde", serde(rename = "startPeriod"))]
pub start_period: crate::OcppTimestamp,
/// Unique identifier of the Tariff that was used to calculate cost. If not provided, then cost was calculated by some other means.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tariff_id: Option<heapless::String<60usize>>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for ChargingPeriod<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.dimensions {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("dimensions"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("dimensions"))?;
}
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// A ChargingPeriodType consists of a start time, and a list of possible values that influence this period, for example: amount of energy charged this period, maximum current during this period etc.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChargingPeriod<
CustomDataType = crate::NoCustomData,
const CHARGING_PERIOD_DIMENSIONS_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub dimensions: Option<
heapless::Vec<CostDimension<CustomDataType>, CHARGING_PERIOD_DIMENSIONS_CAP>,
>,
/// Start timestamp of charging period. A period ends when the next period starts. The last period ends when the session ends.
#[cfg_attr(feature = "serde", serde(rename = "startPeriod"))]
pub start_period: crate::OcppTimestamp,
/// Unique identifier of the Tariff that was used to calculate cost. If not provided, then cost was calculated by some other means.
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tariff_id: Option<heapless::String<60usize>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const CHARGING_PERIOD_DIMENSIONS_CAP: usize,
> crate::validate::Validate
for ChargingPeriod<CustomDataType, CHARGING_PERIOD_DIMENSIONS_CAP> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.dimensions {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("dimensions"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("dimensions"))?;
}
}
Ok(())
}
}
/// Total cost with and without tax. Contains the total of energy, charging time, idle time, fixed and reservation costs including and/or excluding tax.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TotalPrice<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Price/cost excluding tax. Can be absent if _inclTax_ is present.
#[cfg_attr(feature = "serde", serde(rename = "exclTax"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub excl_tax: Option<f64>,
/// Price/cost including tax. Can be absent if _exclTax_ is present.
#[cfg_attr(feature = "serde", serde(rename = "inclTax"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub incl_tax: Option<f64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TotalPrice<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of cost: normal or the minimum or maximum cost.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TariffCostEnum {
NormalCost,
MinCost,
MaxCost,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TariffCostEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This contains the cost calculated during a transaction. It is used both for running cost and final cost of the transaction.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TotalCost<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_time: Option<Price<CustomDataType>>,
/// Currency of the costs in ISO 4217 Code.
pub currency: heapless::String<3usize>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub energy: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub fixed: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "idleTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub idle_time: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationFixed"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_fixed: Option<Price<CustomDataType>>,
#[cfg_attr(feature = "serde", serde(rename = "reservationTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_time: Option<Price<CustomDataType>>,
pub total: TotalPrice<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "typeOfCost"))]
pub type_of_cost: TariffCostEnum,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TotalCost<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingTime"))?;
}
if let Some(value) = &self.energy {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("energy"))?;
}
if let Some(value) = &self.fixed {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("fixed"))?;
}
if let Some(value) = &self.idle_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("idleTime"))?;
}
if let Some(value) = &self.reservation_fixed {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationFixed"))?;
}
if let Some(value) = &self.reservation_time {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("reservationTime"))?;
}
crate::validate::Validate::validate(&self.total)
.map_err(|error| error.in_field("total"))?;
crate::validate::Validate::validate(&self.type_of_cost)
.map_err(|error| error.in_field("typeOfCost"))?;
Ok(())
}
}
/// This contains the calculated usage of energy, charging time and idle time during a transaction.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TotalUsage<CustomDataType = crate::NoCustomData> {
/// Total duration of the charging session (including the duration of charging and not charging), in seconds.
#[cfg_attr(feature = "serde", serde(rename = "chargingTime"))]
pub charging_time: i64,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
pub energy: f64,
/// Total duration of the charging session where the EV was not charging (no energy was transferred between EVSE and EV), in seconds.
#[cfg_attr(feature = "serde", serde(rename = "idleTime"))]
pub idle_time: i64,
/// Total time of reservation in seconds.
#[cfg_attr(feature = "serde", serde(rename = "reservationTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub reservation_time: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TotalUsage<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// CostDetailsType contains the cost as calculated by Charging Station based on provided TariffType.
///
/// NOTE: Reservation is not shown as a _chargingPeriod_, because it took place outside of the transaction.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CostDetails<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingPeriods"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_periods: Option<alloc::vec::Vec<ChargingPeriod<CustomDataType>>>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Optional human-readable reason text in case of failure to calculate.
#[cfg_attr(feature = "serde", serde(rename = "failureReason"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub failure_reason: Option<heapless::String<500usize>>,
/// If set to true, then Charging Station has failed to calculate the cost.
#[cfg_attr(feature = "serde", serde(rename = "failureToCalculate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub failure_to_calculate: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "totalCost"))]
pub total_cost: TotalCost<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "totalUsage"))]
pub total_usage: TotalUsage<CustomDataType>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for CostDetails<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_periods {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingPeriods"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("chargingPeriods"))?;
}
}
crate::validate::Validate::validate(&self.total_cost)
.map_err(|error| error.in_field("totalCost"))?;
crate::validate::Validate::validate(&self.total_usage)
.map_err(|error| error.in_field("totalUsage"))?;
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// CostDetailsType contains the cost as calculated by Charging Station based on provided TariffType.
///
/// NOTE: Reservation is not shown as a _chargingPeriod_, because it took place outside of the transaction.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CostDetails<
CustomDataType = crate::NoCustomData,
const COST_DETAILS_CHARGING_PERIODS_CAP: usize = 8usize,
const CHARGING_PERIOD_DIMENSIONS_CAP: usize = 8usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "chargingPeriods"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_periods: Option<
heapless::Vec<
ChargingPeriod<CustomDataType, CHARGING_PERIOD_DIMENSIONS_CAP>,
COST_DETAILS_CHARGING_PERIODS_CAP,
>,
>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Optional human-readable reason text in case of failure to calculate.
#[cfg_attr(feature = "serde", serde(rename = "failureReason"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub failure_reason: Option<heapless::String<500usize>>,
/// If set to true, then Charging Station has failed to calculate the cost.
#[cfg_attr(feature = "serde", serde(rename = "failureToCalculate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub failure_to_calculate: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "totalCost"))]
pub total_cost: TotalCost<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "totalUsage"))]
pub total_usage: TotalUsage<CustomDataType>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const COST_DETAILS_CHARGING_PERIODS_CAP: usize,
const CHARGING_PERIOD_DIMENSIONS_CAP: usize,
> crate::validate::Validate
for CostDetails<
CustomDataType,
COST_DETAILS_CHARGING_PERIODS_CAP,
CHARGING_PERIOD_DIMENSIONS_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_periods {
crate::validate::check_min_items(value.len(), 1usize)
.map_err(|error| error.in_field("chargingPeriods"))?;
for (index, item) in value.iter().enumerate() {
crate::validate::Validate::validate(item)
.map_err(|error| error.in_index(index).in_field("chargingPeriods"))?;
}
}
crate::validate::Validate::validate(&self.total_cost)
.map_err(|error| error.in_field("totalCost"))?;
crate::validate::Validate::validate(&self.total_usage)
.map_err(|error| error.in_field("totalUsage"))?;
Ok(())
}
}
/// This contains the type of this event.
/// The first TransactionEvent of a transaction SHALL contain: "Started" The last TransactionEvent of a transaction SHALL contain: "Ended" All others SHALL contain: "Updated"
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TransactionEventEnum {
Ended,
Started,
Updated,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TransactionEventEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// *(2.1)* The current preconditioning status of the BMS in the EV. Default value is Unknown.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PreconditioningStatusEnum {
Unknown,
Ready,
NotReady,
Preconditioning,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PreconditioningStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Current charging state, is required when state
/// has changed. Omitted when there is no communication between EVSE and EV, because no cable is plugged in.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChargingStateEnum {
EVConnected,
Charging,
SuspendedEV,
SuspendedEVSE,
Idle,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ChargingStateEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// The _stoppedReason_ is the reason/event that initiated the process of stopping the transaction. It will normally be the user stopping authorization via card (Local or MasterPass) or app (Remote), but it can also be CSMS revoking authorization (DeAuthorized), or disconnecting the EV when TxStopPoint = EVConnected (EVDisconnected). Most other reasons are related to technical faults or energy limitations. +
/// MAY only be omitted when _stoppedReason_ is "Local"
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReasonEnum {
DeAuthorized,
EmergencyStop,
EnergyLimitReached,
EVDisconnected,
GroundFault,
ImmediateReset,
MasterPass,
Local,
LocalOutOfCredit,
Other,
OvercurrentFault,
PowerLoss,
PowerQuality,
Reboot,
Remote,
SOCLimitReached,
StoppedByEV,
TimeLimitReached,
Timeout,
ReqEnergyTransferRejected,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for ReasonEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Cost, energy, time or SoC limit for a transaction.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TransactionLimit<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Maximum allowed cost of transaction in currency of tariff.
#[cfg_attr(feature = "serde", serde(rename = "maxCost"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_cost: Option<f64>,
/// Maximum allowed energy in Wh to charge in transaction.
#[cfg_attr(feature = "serde", serde(rename = "maxEnergy"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_energy: Option<f64>,
/// Maximum State of Charge of EV in percentage.
#[cfg_attr(feature = "serde", serde(rename = "maxSoC"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_so_c: Option<i64>,
/// Maximum duration of transaction in seconds from start to end.
#[cfg_attr(feature = "serde", serde(rename = "maxTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_time: Option<i64>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for TransactionLimit<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = self.max_so_c {
crate::validate::check_min_i64(value, 0i64)
.map_err(|error| error.in_field("maxSoC"))?;
crate::validate::check_max_i64(value, 100i64)
.map_err(|error| error.in_field("maxSoC"))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Transaction<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "chargingState"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub charging_state: Option<ChargingStateEnum>,
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
#[cfg_attr(feature = "serde", serde(rename = "operationMode"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub operation_mode: Option<OperationModeEnum>,
/// The ID given to remote start request (<<requeststarttransactionrequest, RequestStartTransactionRequest>>. This enables to CSMS to match the started transaction to the given start request.
#[cfg_attr(feature = "serde", serde(rename = "remoteStartId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub remote_start_id: Option<i64>,
#[cfg_attr(feature = "serde", serde(rename = "stoppedReason"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub stopped_reason: Option<ReasonEnum>,
/// *(2.1)* Id of tariff in use for transaction
#[cfg_attr(feature = "serde", serde(rename = "tariffId"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub tariff_id: Option<heapless::String<60usize>>,
/// Contains the total time that energy flowed from EVSE to EV during the transaction (in seconds). Note that timeSpentCharging is smaller or equal to the duration of the transaction.
#[cfg_attr(feature = "serde", serde(rename = "timeSpentCharging"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub time_spent_charging: Option<i64>,
/// This contains the Id of the transaction.
#[cfg_attr(feature = "serde", serde(rename = "transactionId"))]
pub transaction_id: heapless::String<36usize>,
#[cfg_attr(feature = "serde", serde(rename = "transactionLimit"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub transaction_limit: Option<TransactionLimit<CustomDataType>>,
}
#[cfg(feature = "validate")]
impl<CustomDataType> crate::validate::Validate for Transaction<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
if let Some(value) = &self.charging_state {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("chargingState"))?;
}
if let Some(value) = &self.operation_mode {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("operationMode"))?;
}
if let Some(value) = &self.stopped_reason {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("stoppedReason"))?;
}
if let Some(value) = &self.transaction_limit {
crate::validate::Validate::validate(value)
.map_err(|error| error.in_field("transactionLimit"))?;
}
Ok(())
}
}
/// Reason the Charging Station sends this message to the CSMS
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TriggerReasonEnum {
AbnormalCondition,
Authorized,
CablePluggedIn,
ChargingRateChanged,
ChargingStateChanged,
CostLimitReached,
Deauthorized,
EnergyLimitReached,
EVCommunicationLost,
EVConnectTimeout,
EVDeparted,
EVDetected,
LimitSet,
MeterValueClock,
MeterValuePeriodic,
OperationModeChanged,
RemoteStart,
RemoteStop,
ResetCommand,
RunningCost,
SignedDataReceived,
SoCLimitReached,
StopAuthorized,
TariffChanged,
TariffNotAccepted,
TimeLimitReached,
Trigger,
TxResumed,
UnlockCommand,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TriggerReasonEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Type of message to be triggered.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MessageTriggerEnum {
BootNotification,
LogStatusNotification,
FirmwareStatusNotification,
Heartbeat,
MeterValues,
SignChargingStationCertificate,
SignV2GCertificate,
SignV2G20Certificate,
StatusNotification,
TransactionEvent,
SignCombinedCertificate,
PublishFirmwareStatusNotification,
CustomTrigger,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for MessageTriggerEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates whether the Charging Station will send the requested notification or not.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TriggerMessageStatusEnum {
Accepted,
Rejected,
NotImplemented,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for TriggerMessageStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// This indicates whether the Charging Station has unlocked the connector.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum UnlockStatusEnum {
Unlocked,
UnlockFailed,
OngoingAuthorizedTransaction,
UnknownConnector,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for UnlockStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Indicates whether the Local Controller succeeded in unpublishing the firmware.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum UnpublishFirmwareStatusEnum {
DownloadOngoing,
NoFirmware,
Unpublished,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for UnpublishFirmwareStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
/// Represents a copy of the firmware that can be loaded/updated on the Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Firmware<CustomDataType = crate::NoCustomData> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Date and time at which the firmware shall be installed.
#[cfg_attr(feature = "serde", serde(rename = "installDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub install_date_time: Option<crate::OcppTimestamp>,
/// URI defining the origin of the firmware.
pub location: alloc::string::String,
/// Date and time at which the firmware shall be retrieved.
#[cfg_attr(feature = "serde", serde(rename = "retrieveDateTime"))]
pub retrieve_date_time: crate::OcppTimestamp,
/// Base64 encoded firmware signature.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signature: Option<alloc::string::String>,
/// Certificate with which the firmware was signed.
/// PEM encoded X.509 certificate.
#[cfg_attr(feature = "serde", serde(rename = "signingCertificate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signing_certificate: Option<alloc::string::String>,
}
#[cfg(all(feature = "validate", feature = "alloc"))]
impl<CustomDataType> crate::validate::Validate for Firmware<CustomDataType> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.location, 2000usize)
.map_err(|error| error.in_field("location"))?;
if let Some(value) = &self.signature {
crate::validate::check_max_length(value, 800usize)
.map_err(|error| error.in_field("signature"))?;
}
if let Some(value) = &self.signing_certificate {
crate::validate::check_max_length(value, 5500usize)
.map_err(|error| error.in_field("signingCertificate"))?;
}
Ok(())
}
}
#[cfg(not(feature = "alloc"))]
/// Represents a copy of the firmware that can be loaded/updated on the Charging Station.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Firmware<
CustomDataType = crate::NoCustomData,
const FIRMWARE_LOCATION_CAP: usize = 1024usize,
const FIRMWARE_SIGNATURE_CAP: usize = 800usize,
const FIRMWARE_SIGNING_CERTIFICATE_CAP: usize = 1024usize,
> {
#[cfg_attr(feature = "serde", serde(rename = "customData"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub custom_data: Option<CustomDataType>,
/// Date and time at which the firmware shall be installed.
#[cfg_attr(feature = "serde", serde(rename = "installDateTime"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub install_date_time: Option<crate::OcppTimestamp>,
/// URI defining the origin of the firmware.
pub location: heapless::String<FIRMWARE_LOCATION_CAP>,
/// Date and time at which the firmware shall be retrieved.
#[cfg_attr(feature = "serde", serde(rename = "retrieveDateTime"))]
pub retrieve_date_time: crate::OcppTimestamp,
/// Base64 encoded firmware signature.
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signature: Option<heapless::String<FIRMWARE_SIGNATURE_CAP>>,
/// Certificate with which the firmware was signed.
/// PEM encoded X.509 certificate.
#[cfg_attr(feature = "serde", serde(rename = "signingCertificate"))]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub signing_certificate: Option<heapless::String<FIRMWARE_SIGNING_CERTIFICATE_CAP>>,
}
#[cfg(all(feature = "validate", not(feature = "alloc")))]
impl<
CustomDataType,
const FIRMWARE_LOCATION_CAP: usize,
const FIRMWARE_SIGNATURE_CAP: usize,
const FIRMWARE_SIGNING_CERTIFICATE_CAP: usize,
> crate::validate::Validate
for Firmware<
CustomDataType,
FIRMWARE_LOCATION_CAP,
FIRMWARE_SIGNATURE_CAP,
FIRMWARE_SIGNING_CERTIFICATE_CAP,
> {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
crate::validate::check_max_length(&self.location, 2000usize)
.map_err(|error| error.in_field("location"))?;
if let Some(value) = &self.signature {
crate::validate::check_max_length(value, 800usize)
.map_err(|error| error.in_field("signature"))?;
}
if let Some(value) = &self.signing_certificate {
crate::validate::check_max_length(value, 5500usize)
.map_err(|error| error.in_field("signingCertificate"))?;
}
Ok(())
}
}
/// This field indicates whether the Charging Station was able to accept the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum UpdateFirmwareStatusEnum {
Accepted,
Rejected,
AcceptedCanceled,
InvalidCertificate,
RevokedCertificate,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for UpdateFirmwareStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}
/// Result of the request.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PriorityChargingStatusEnum {
Accepted,
Rejected,
NoProfile,
}
#[cfg(feature = "validate")]
impl crate::validate::Validate for PriorityChargingStatusEnum {
fn validate(&self) -> Result<(), crate::validate::ValidationError> {
Ok(())
}
}