// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Kevin Vavelin, Codetics (https://codetics.fr)
//! OCPP 2.1 composite datatypes.
use ocpp_core::DateTime;
use ocpp_core::validate::{self as v, Path, Validate, Violation};
use serde::{Deserialize, Serialize};
use crate::enums::*;
/// EV AC charging parameters for ISO 15118-2
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ACChargingParameters {
/// 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
#[serde(rename = "energyAmount")]
pub energy_amount: f64,
/// Minimum current (amps) supported by the electric vehicle (per phase).
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMinCurrent
#[serde(rename = "evMinCurrent")]
pub ev_min_current: f64,
/// Maximum current (amps) supported by the electric vehicle (per phase). Includes cable capacity.
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMaxCurrent
#[serde(rename = "evMaxCurrent")]
pub ev_max_current: f64,
/// Maximum voltage supported by the electric vehicle.
/// Relates to: +
/// *ISO 15118-2*: AC_EVChargeParameterType: EVMaxVoltage
#[serde(rename = "evMaxVoltage")]
pub ev_max_voltage: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ACChargingParameters {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct APN {
/// The Access Point Name as an URL.
#[serde(rename = "apn")]
pub apn: String,
/// APN username.
#[serde(
rename = "apnUserName",
default,
skip_serializing_if = "Option::is_none"
)]
pub apn_user_name: Option<String>,
/// *(2.1)* APN Password.
#[serde(
rename = "apnPassword",
default,
skip_serializing_if = "Option::is_none"
)]
pub apn_password: Option<String>,
/// SIM card pin code.
#[serde(rename = "simPin", default, skip_serializing_if = "Option::is_none")]
pub sim_pin: Option<i64>,
/// Preferred network, written as MCC and MNC concatenated. See note.
#[serde(
rename = "preferredNetwork",
default,
skip_serializing_if = "Option::is_none"
)]
pub preferred_network: Option<String>,
/// Default: false. Use only the preferred Network, do
/// not dial in when not available. See Note.
#[serde(
rename = "useOnlyPreferredNetwork",
default,
skip_serializing_if = "Option::is_none"
)]
pub use_only_preferred_network: Option<bool>,
#[serde(rename = "apnAuthentication")]
pub apn_authentication: APNAuthenticationEnum,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for APN {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.apn;
let p = path.field("apn");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.apn_user_name {
let p = path.field("apnUserName");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.apn_password {
let p = path.field("apnPassword");
v::max_length(x, 64, &p)?;
}
if let Some(x) = &self.preferred_network {
let p = path.field("preferredNetwork");
v::max_length(x, 6, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AbsolutePriceSchedule {
/// Starting point of price schedule.
#[serde(rename = "timeAnchor")]
pub time_anchor: DateTime,
/// Unique ID of price schedule
#[serde(rename = "priceScheduleID")]
pub price_schedule_id: i64,
/// Description of the price schedule.
#[serde(
rename = "priceScheduleDescription",
default,
skip_serializing_if = "Option::is_none"
)]
pub price_schedule_description: Option<String>,
/// Currency according to ISO 4217.
#[serde(rename = "currency")]
pub currency: String,
/// String that indicates what language is used for the human readable strings in the price schedule. Based on ISO 639.
#[serde(rename = "language")]
pub language: String,
/// 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.
#[serde(rename = "priceAlgorithm")]
pub price_algorithm: String,
#[serde(
rename = "minimumCost",
default,
skip_serializing_if = "Option::is_none"
)]
pub minimum_cost: Option<RationalNumber>,
#[serde(
rename = "maximumCost",
default,
skip_serializing_if = "Option::is_none"
)]
pub maximum_cost: Option<RationalNumber>,
#[serde(rename = "priceRuleStacks")]
pub price_rule_stacks: Vec<PriceRuleStack>,
#[serde(rename = "taxRules", default, skip_serializing_if = "Option::is_none")]
pub tax_rules: Option<Vec<TaxRule>>,
#[serde(
rename = "overstayRuleList",
default,
skip_serializing_if = "Option::is_none"
)]
pub overstay_rule_list: Option<OverstayRuleList>,
#[serde(
rename = "additionalSelectedServices",
default,
skip_serializing_if = "Option::is_none"
)]
pub additional_selected_services: Option<Vec<AdditionalSelectedServices>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for AbsolutePriceSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.price_schedule_id;
let p = path.field("priceScheduleID");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.price_schedule_description {
let p = path.field("priceScheduleDescription");
v::max_length(x, 160, &p)?;
}
{
let x = &self.currency;
let p = path.field("currency");
v::max_length(x, 3, &p)?;
}
{
let x = &self.language;
let p = path.field("language");
v::max_length(x, 8, &p)?;
}
{
let x = &self.price_algorithm;
let p = path.field("priceAlgorithm");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.minimum_cost {
let p = path.field("minimumCost");
x.validate(&p)?;
}
if let Some(x) = &self.maximum_cost {
let p = path.field("maximumCost");
x.validate(&p)?;
}
{
let x = &self.price_rule_stacks;
let p = path.field("priceRuleStacks");
v::items(x, Some(1), Some(1024), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.tax_rules {
let p = path.field("taxRules");
v::items(x, Some(1), Some(10), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.overstay_rule_list {
let p = path.field("overstayRuleList");
x.validate(&p)?;
}
if let Some(x) = &self.additional_selected_services {
let p = path.field("additionalSelectedServices");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AdditionalInfo {
/// *(2.1)* This field specifies the additional IdToken.
#[serde(rename = "additionalIdToken")]
pub additional_id_token: String,
/// _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_.
#[serde(rename = "type")]
pub r#type: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for AdditionalInfo {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.additional_id_token;
let p = path.field("additionalIdToken");
v::max_length(x, 255, &p)?;
}
{
let x = &self.r#type;
let p = path.field("type");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AdditionalSelectedServices {
#[serde(rename = "serviceFee")]
pub service_fee: RationalNumber,
/// Human readable string to identify this service.
#[serde(rename = "serviceName")]
pub service_name: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for AdditionalSelectedServices {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.service_fee;
let p = path.field("serviceFee");
x.validate(&p)?;
}
{
let x = &self.service_name;
let p = path.field("serviceName");
v::max_length(x, 80, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* A generic address format.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Address {
/// Name of person/company
#[serde(rename = "name")]
pub name: String,
/// Address line 1
#[serde(rename = "address1")]
pub address1: String,
/// Address line 2
#[serde(rename = "address2", default, skip_serializing_if = "Option::is_none")]
pub address2: Option<String>,
/// City
#[serde(rename = "city")]
pub city: String,
/// Postal code
#[serde(
rename = "postalCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub postal_code: Option<String>,
/// Country name
#[serde(rename = "country")]
pub country: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Address {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.name;
let p = path.field("name");
v::max_length(x, 50, &p)?;
}
{
let x = &self.address1;
let p = path.field("address1");
v::max_length(x, 100, &p)?;
}
if let Some(x) = &self.address2 {
let p = path.field("address2");
v::max_length(x, 100, &p)?;
}
{
let x = &self.city;
let p = path.field("city");
v::max_length(x, 100, &p)?;
}
if let Some(x) = &self.postal_code {
let p = path.field("postalCode");
v::max_length(x, 20, &p)?;
}
{
let x = &self.country;
let p = path.field("country");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Contains the identifier to use for authorization.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AuthorizationData {
#[serde(rename = "idToken")]
pub id_token: IdToken,
#[serde(
rename = "idTokenInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub id_token_info: Option<IdTokenInfo>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for AuthorizationData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id_token;
let p = path.field("idToken");
x.validate(&p)?;
}
if let Some(x) = &self.id_token_info {
let p = path.field("idTokenInfo");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BatteryData {
/// Slot number where battery is inserted or removed.
#[serde(rename = "evseId")]
pub evse_id: i64,
/// Serial number of battery.
#[serde(rename = "serialNumber")]
pub serial_number: String,
/// State of charge
#[serde(rename = "soC")]
pub so_c: f64,
/// State of health
#[serde(rename = "soH")]
pub so_h: f64,
/// Production date of battery.
#[serde(
rename = "productionDate",
default,
skip_serializing_if = "Option::is_none"
)]
pub production_date: Option<DateTime>,
/// Vendor-specific info from battery in undefined format.
#[serde(
rename = "vendorInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub vendor_info: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for BatteryData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.evse_id;
let p = path.field("evseId");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.serial_number;
let p = path.field("serialNumber");
v::max_length(x, 50, &p)?;
}
{
let x = &self.so_c;
let p = path.field("soC");
v::minimum(*x, 0.0, &p)?;
v::maximum(*x, 100.0, &p)?;
}
{
let x = &self.so_h;
let p = path.field("soH");
v::minimum(*x, 0.0, &p)?;
v::maximum(*x, 100.0, &p)?;
}
if let Some(x) = &self.vendor_info {
let p = path.field("vendorInfo");
v::max_length(x, 500, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CertificateHashData {
#[serde(rename = "hashAlgorithm")]
pub hash_algorithm: HashAlgorithmEnum,
/// 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.
#[serde(rename = "issuerNameHash")]
pub issuer_name_hash: String,
/// 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.
#[serde(rename = "issuerKeyHash")]
pub issuer_key_hash: String,
/// The string representation of the
/// hexadecimal value of the serial number without the
/// prefix "0x" and without leading zeroes.
#[serde(rename = "serialNumber")]
pub serial_number: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CertificateHashData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.issuer_name_hash;
let p = path.field("issuerNameHash");
v::max_length(x, 128, &p)?;
}
{
let x = &self.issuer_key_hash;
let p = path.field("issuerKeyHash");
v::max_length(x, 128, &p)?;
}
{
let x = &self.serial_number;
let p = path.field("serialNumber");
v::max_length(x, 40, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CertificateHashDataChain {
#[serde(rename = "certificateHashData")]
pub certificate_hash_data: CertificateHashData,
#[serde(rename = "certificateType")]
pub certificate_type: GetCertificateIdUseEnum,
#[serde(
rename = "childCertificateHashData",
default,
skip_serializing_if = "Option::is_none"
)]
pub child_certificate_hash_data: Option<Vec<CertificateHashData>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CertificateHashDataChain {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.certificate_hash_data;
let p = path.field("certificateHashData");
x.validate(&p)?;
}
if let Some(x) = &self.child_certificate_hash_data {
let p = path.field("childCertificateHashData");
v::items(x, Some(1), Some(4), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Revocation status of certificate
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CertificateStatus {
#[serde(rename = "certificateHashData")]
pub certificate_hash_data: CertificateHashData,
#[serde(rename = "source")]
pub source: CertificateStatusSourceEnum,
#[serde(rename = "status")]
pub status: CertificateStatusEnum,
#[serde(rename = "nextUpdate")]
pub next_update: DateTime,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CertificateStatus {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.certificate_hash_data;
let p = path.field("certificateHashData");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Data necessary to request the revocation status of a certificate.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CertificateStatusRequestInfo {
#[serde(rename = "certificateHashData")]
pub certificate_hash_data: CertificateHashData,
#[serde(rename = "source")]
pub source: CertificateStatusSourceEnum,
/// URL(s) of _source_.
#[serde(rename = "urls")]
pub urls: Vec<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CertificateStatusRequestInfo {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.certificate_hash_data;
let p = path.field("certificateHashData");
x.validate(&p)?;
}
{
let x = &self.urls;
let p = path.field("urls");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
v::max_length(it0, 2000, &p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingLimit {
/// Represents the source of the charging limit. Values defined in appendix as ChargingLimitSourceEnumStringType.
#[serde(rename = "chargingLimitSource")]
pub charging_limit_source: String,
/// *(2.1)* True when the reported limit concerns local generation that is providing extra capacity, instead of a limitation.
#[serde(
rename = "isLocalGeneration",
default,
skip_serializing_if = "Option::is_none"
)]
pub is_local_generation: Option<bool>,
/// Indicates whether the charging limit is critical for the grid.
#[serde(
rename = "isGridCritical",
default,
skip_serializing_if = "Option::is_none"
)]
pub is_grid_critical: Option<bool>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingLimit {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.charging_limit_source;
let p = path.field("chargingLimitSource");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingNeeds {
#[serde(
rename = "acChargingParameters",
default,
skip_serializing_if = "Option::is_none"
)]
pub ac_charging_parameters: Option<ACChargingParameters>,
#[serde(
rename = "derChargingParameters",
default,
skip_serializing_if = "Option::is_none"
)]
pub der_charging_parameters: Option<DERChargingParameters>,
#[serde(
rename = "evEnergyOffer",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_energy_offer: Option<EVEnergyOffer>,
#[serde(rename = "requestedEnergyTransfer")]
pub requested_energy_transfer: EnergyTransferModeEnum,
#[serde(
rename = "dcChargingParameters",
default,
skip_serializing_if = "Option::is_none"
)]
pub dc_charging_parameters: Option<DCChargingParameters>,
#[serde(
rename = "v2xChargingParameters",
default,
skip_serializing_if = "Option::is_none"
)]
pub v2x_charging_parameters: Option<V2XChargingParameters>,
/// *(2.1)* Modes of energy transfer that are marked as available by EV.
#[serde(
rename = "availableEnergyTransfer",
default,
skip_serializing_if = "Option::is_none"
)]
pub available_energy_transfer: Option<Vec<EnergyTransferModeEnum>>,
#[serde(
rename = "controlMode",
default,
skip_serializing_if = "Option::is_none"
)]
pub control_mode: Option<ControlModeEnum>,
#[serde(
rename = "mobilityNeedsMode",
default,
skip_serializing_if = "Option::is_none"
)]
pub mobility_needs_mode: Option<MobilityNeedsModeEnum>,
/// Estimated departure time of the EV. +
/// *ISO 15118-2:* AC/DC_EVChargeParameterType: DepartureTime +
/// *ISO 15118-20:* Dynamic/Scheduled_SEReqControlModeType: DepartureTIme
#[serde(
rename = "departureTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub departure_time: Option<DateTime>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingNeeds {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.ac_charging_parameters {
let p = path.field("acChargingParameters");
x.validate(&p)?;
}
if let Some(x) = &self.der_charging_parameters {
let p = path.field("derChargingParameters");
x.validate(&p)?;
}
if let Some(x) = &self.ev_energy_offer {
let p = path.field("evEnergyOffer");
x.validate(&p)?;
}
if let Some(x) = &self.dc_charging_parameters {
let p = path.field("dcChargingParameters");
x.validate(&p)?;
}
if let Some(x) = &self.v2x_charging_parameters {
let p = path.field("v2xChargingParameters");
x.validate(&p)?;
}
if let Some(x) = &self.available_energy_transfer {
let p = path.field("availableEnergyTransfer");
v::items(x, Some(1), None, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingPeriod {
#[serde(
rename = "dimensions",
default,
skip_serializing_if = "Option::is_none"
)]
pub dimensions: Option<Vec<CostDimension>>,
/// Unique identifier of the Tariff that was used to calculate cost. If not provided, then cost was calculated by some other means.
#[serde(rename = "tariffId", default, skip_serializing_if = "Option::is_none")]
pub tariff_id: Option<String>,
/// Start timestamp of charging period. A period ends when the next period starts. The last period ends when the session ends.
#[serde(rename = "startPeriod")]
pub start_period: DateTime,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingPeriod {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.dimensions {
let p = path.field("dimensions");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.tariff_id {
let p = path.field("tariffId");
v::max_length(x, 60, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingProfile {
/// 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.
#[serde(rename = "id")]
pub id: i64,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[serde(rename = "stackLevel")]
pub stack_level: i64,
#[serde(rename = "chargingProfilePurpose")]
pub charging_profile_purpose: ChargingProfilePurposeEnum,
#[serde(rename = "chargingProfileKind")]
pub charging_profile_kind: ChargingProfileKindEnum,
#[serde(
rename = "recurrencyKind",
default,
skip_serializing_if = "Option::is_none"
)]
pub recurrency_kind: Option<RecurrencyKindEnum>,
/// 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.
#[serde(rename = "validFrom", default, skip_serializing_if = "Option::is_none")]
pub valid_from: Option<DateTime>,
/// Point in time at which the profile stops to be valid. If absent, the profile is valid until it is replaced by another profile.
#[serde(rename = "validTo", default, skip_serializing_if = "Option::is_none")]
pub valid_to: Option<DateTime>,
/// 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.
#[serde(
rename = "transactionId",
default,
skip_serializing_if = "Option::is_none"
)]
pub transaction_id: Option<String>,
/// *(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.
#[serde(
rename = "maxOfflineDuration",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_offline_duration: Option<i64>,
#[serde(rename = "chargingSchedule")]
pub charging_schedule: Vec<ChargingSchedule>,
/// *(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.
#[serde(
rename = "invalidAfterOfflineDuration",
default,
skip_serializing_if = "Option::is_none"
)]
pub invalid_after_offline_duration: Option<bool>,
/// *(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.
#[serde(
rename = "dynUpdateInterval",
default,
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.
#[serde(
rename = "dynUpdateTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub dyn_update_time: Option<DateTime>,
/// *(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.
#[serde(
rename = "priceScheduleSignature",
default,
skip_serializing_if = "Option::is_none"
)]
pub price_schedule_signature: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingProfile {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.stack_level;
let p = path.field("stackLevel");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.transaction_id {
let p = path.field("transactionId");
v::max_length(x, 36, &p)?;
}
{
let x = &self.charging_schedule;
let p = path.field("chargingSchedule");
v::items(x, Some(1), Some(3), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.price_schedule_signature {
let p = path.field("priceScheduleSignature");
v::max_length(x, 256, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// A ChargingProfileCriterionType is a filter for charging profiles to be selected by a GetChargingProfilesRequest.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingProfileCriterion {
#[serde(
rename = "chargingProfilePurpose",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_profile_purpose: Option<ChargingProfilePurposeEnum>,
/// Value determining level in hierarchy stack of profiles. Higher values have precedence over lower values. Lowest level is 0.
#[serde(
rename = "stackLevel",
default,
skip_serializing_if = "Option::is_none"
)]
pub stack_level: Option<i64>,
/// 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>>
#[serde(
rename = "chargingProfileId",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_profile_id: Option<Vec<i64>>,
/// 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.
#[serde(
rename = "chargingLimitSource",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_limit_source: Option<Vec<String>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingProfileCriterion {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.stack_level {
let p = path.field("stackLevel");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.charging_profile_id {
let p = path.field("chargingProfileId");
v::items(x, Some(1), None, &p)?;
}
if let Some(x) = &self.charging_limit_source {
let p = path.field("chargingLimitSource");
v::items(x, Some(1), Some(4), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
v::max_length(it0, 20, &p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingSchedule {
#[serde(rename = "id")]
pub id: i64,
#[serde(
rename = "limitAtSoC",
default,
skip_serializing_if = "Option::is_none"
)]
pub limit_at_so_c: Option<LimitAtSoC>,
/// Starting point of an absolute schedule or recurring schedule.
#[serde(
rename = "startSchedule",
default,
skip_serializing_if = "Option::is_none"
)]
pub start_schedule: Option<DateTime>,
/// 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.
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<i64>,
#[serde(rename = "chargingRateUnit")]
pub charging_rate_unit: ChargingRateUnitEnum,
/// 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.
#[serde(
rename = "minChargingRate",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_charging_rate: Option<f64>,
/// *(2.1)* Power tolerance when following EVPowerProfile.
#[serde(
rename = "powerTolerance",
default,
skip_serializing_if = "Option::is_none"
)]
pub power_tolerance: Option<f64>,
/// *(2.1)* Id of this element for referencing in a signature.
#[serde(
rename = "signatureId",
default,
skip_serializing_if = "Option::is_none"
)]
pub signature_id: Option<i64>,
/// *(2.1)* Base64 encoded hash (SHA256 for ISO 15118-2, SHA512 for ISO 15118-20) of the EXI price schedule element. Used in signature.
#[serde(
rename = "digestValue",
default,
skip_serializing_if = "Option::is_none"
)]
pub digest_value: Option<String>,
/// *(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.
#[serde(
rename = "useLocalTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub use_local_time: Option<bool>,
#[serde(rename = "chargingSchedulePeriod")]
pub charging_schedule_period: Vec<ChargingSchedulePeriod>,
/// *(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.
#[serde(
rename = "randomizedDelay",
default,
skip_serializing_if = "Option::is_none"
)]
pub randomized_delay: Option<i64>,
#[serde(
rename = "salesTariff",
default,
skip_serializing_if = "Option::is_none"
)]
pub sales_tariff: Option<SalesTariff>,
#[serde(
rename = "absolutePriceSchedule",
default,
skip_serializing_if = "Option::is_none"
)]
pub absolute_price_schedule: Option<AbsolutePriceSchedule>,
#[serde(
rename = "priceLevelSchedule",
default,
skip_serializing_if = "Option::is_none"
)]
pub price_level_schedule: Option<PriceLevelSchedule>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.limit_at_so_c {
let p = path.field("limitAtSoC");
x.validate(&p)?;
}
if let Some(x) = &self.signature_id {
let p = path.field("signatureId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.digest_value {
let p = path.field("digestValue");
v::max_length(x, 88, &p)?;
}
{
let x = &self.charging_schedule_period;
let p = path.field("chargingSchedulePeriod");
v::items(x, Some(1), Some(1024), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.randomized_delay {
let p = path.field("randomizedDelay");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.sales_tariff {
let p = path.field("salesTariff");
x.validate(&p)?;
}
if let Some(x) = &self.absolute_price_schedule {
let p = path.field("absolutePriceSchedule");
x.validate(&p)?;
}
if let Some(x) = &self.price_level_schedule {
let p = path.field("priceLevelSchedule");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingSchedulePeriod {
/// Start of the period, in seconds from the start of schedule. The value of StartPeriod also defines the stop time of the previous period.
#[serde(rename = "startPeriod")]
pub start_period: i64,
/// 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.
#[serde(rename = "limit", default, skip_serializing_if = "Option::is_none")]
pub limit: Option<f64>,
/// *(2.1)* Charging rate limit on phase L2 in the applicable _chargingRateUnit_.
#[serde(rename = "limit_L2", default, skip_serializing_if = "Option::is_none")]
pub limit_l2: Option<f64>,
/// *(2.1)* Charging rate limit on phase L3 in the applicable _chargingRateUnit_.
#[serde(rename = "limit_L3", default, 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.
#[serde(
rename = "numberPhases",
default,
skip_serializing_if = "Option::is_none"
)]
pub number_phases: Option<i64>,
/// 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.
#[serde(
rename = "phaseToUse",
default,
skip_serializing_if = "Option::is_none"
)]
pub phase_to_use: Option<i64>,
/// *(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.
#[serde(
rename = "dischargeLimit",
default,
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.
#[serde(
rename = "dischargeLimit_L2",
default,
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.
#[serde(
rename = "dischargeLimit_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub discharge_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.
#[serde(rename = "setpoint", default, skip_serializing_if = "Option::is_none")]
pub setpoint: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L2 as close as possible.
#[serde(
rename = "setpoint_L2",
default,
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.
#[serde(
rename = "setpoint_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub setpoint_l3: 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.
#[serde(
rename = "setpointReactive",
default,
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.
#[serde(
rename = "setpointReactive_L2",
default,
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.
#[serde(
rename = "setpointReactive_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub setpoint_reactive_l3: Option<f64>,
/// *(2.1)* If true, the EV should attempt to keep the BMS preconditioned for this time interval.
#[serde(
rename = "preconditioningRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub preconditioning_request: Option<bool>,
/// *(2.1)* If true, the EVSE must turn off power electronics/modules associated with this transaction. Default value when absent is false.
#[serde(rename = "evseSleep", default, skip_serializing_if = "Option::is_none")]
pub evse_sleep: Option<bool>,
/// *(2.1)* Power value that, when present, is used as a baseline on top of which values from _v2xFreqWattCurve_ and _v2xSignalWattCurve_ are added.
#[serde(
rename = "v2xBaseline",
default,
skip_serializing_if = "Option::is_none"
)]
pub v2x_baseline: Option<f64>,
#[serde(
rename = "operationMode",
default,
skip_serializing_if = "Option::is_none"
)]
pub operation_mode: Option<OperationModeEnum>,
#[serde(
rename = "v2xFreqWattCurve",
default,
skip_serializing_if = "Option::is_none"
)]
pub v2x_freq_watt_curve: Option<Vec<V2XFreqWattPoint>>,
#[serde(
rename = "v2xSignalWattCurve",
default,
skip_serializing_if = "Option::is_none"
)]
pub v2x_signal_watt_curve: Option<Vec<V2XSignalWattPoint>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingSchedulePeriod {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.number_phases {
let p = path.field("numberPhases");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 3i64, &p)?;
}
if let Some(x) = &self.phase_to_use {
let p = path.field("phaseToUse");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 3i64, &p)?;
}
if let Some(x) = &self.discharge_limit {
let p = path.field("dischargeLimit");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.discharge_limit_l2 {
let p = path.field("dischargeLimit_L2");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.discharge_limit_l3 {
let p = path.field("dischargeLimit_L3");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.v2x_freq_watt_curve {
let p = path.field("v2xFreqWattCurve");
v::items(x, Some(1), Some(20), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.v2x_signal_watt_curve {
let p = path.field("v2xSignalWattCurve");
v::items(x, Some(1), Some(20), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Updates to a ChargingSchedulePeriodType for dynamic charging profiles.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingScheduleUpdate {
/// 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.
#[serde(rename = "limit", default, skip_serializing_if = "Option::is_none")]
pub limit: Option<f64>,
/// *(2.1)* Charging rate limit on phase L2 in the applicable _chargingRateUnit_.
#[serde(rename = "limit_L2", default, skip_serializing_if = "Option::is_none")]
pub limit_l2: Option<f64>,
/// *(2.1)* Charging rate limit on phase L3 in the applicable _chargingRateUnit_.
#[serde(rename = "limit_L3", default, skip_serializing_if = "Option::is_none")]
pub limit_l3: Option<f64>,
/// *(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.
#[serde(
rename = "dischargeLimit",
default,
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.
#[serde(
rename = "dischargeLimit_L2",
default,
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.
#[serde(
rename = "dischargeLimit_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub discharge_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.
#[serde(rename = "setpoint", default, skip_serializing_if = "Option::is_none")]
pub setpoint: Option<f64>,
/// *(2.1)* Setpoint in _chargingRateUnit_ that the EV should follow on phase L2 as close as possible.
#[serde(
rename = "setpoint_L2",
default,
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.
#[serde(
rename = "setpoint_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub setpoint_l3: 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.
#[serde(
rename = "setpointReactive",
default,
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.
#[serde(
rename = "setpointReactive_L2",
default,
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.
#[serde(
rename = "setpointReactive_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub setpoint_reactive_l3: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingScheduleUpdate {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.discharge_limit {
let p = path.field("dischargeLimit");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.discharge_limit_l2 {
let p = path.field("dischargeLimit_L2");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.discharge_limit_l3 {
let p = path.field("dischargeLimit_L3");
v::maximum(*x, 0.0, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// The physical system where an Electrical Vehicle (EV) can be charged.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChargingStation {
/// Vendor-specific device identifier.
#[serde(
rename = "serialNumber",
default,
skip_serializing_if = "Option::is_none"
)]
pub serial_number: Option<String>,
/// Defines the model of the device.
#[serde(rename = "model")]
pub model: String,
#[serde(rename = "modem", default, skip_serializing_if = "Option::is_none")]
pub modem: Option<Modem>,
/// Identifies the vendor (not necessarily in a unique manner).
#[serde(rename = "vendorName")]
pub vendor_name: String,
/// This contains the firmware version of the Charging Station.
#[serde(
rename = "firmwareVersion",
default,
skip_serializing_if = "Option::is_none"
)]
pub firmware_version: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ChargingStation {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.serial_number {
let p = path.field("serialNumber");
v::max_length(x, 25, &p)?;
}
{
let x = &self.model;
let p = path.field("model");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.modem {
let p = path.field("modem");
x.validate(&p)?;
}
{
let x = &self.vendor_name;
let p = path.field("vendorName");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.firmware_version {
let p = path.field("firmwareVersion");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// A ClearChargingProfileType is a filter for charging profiles to be cleared by ClearChargingProfileRequest.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClearChargingProfile {
/// 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.
#[serde(rename = "evseId", default, skip_serializing_if = "Option::is_none")]
pub evse_id: Option<i64>,
#[serde(
rename = "chargingProfilePurpose",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_profile_purpose: Option<ChargingProfilePurposeEnum>,
/// Specifies the stackLevel for which charging profiles will be cleared, if they meet the other criteria in the request.
#[serde(
rename = "stackLevel",
default,
skip_serializing_if = "Option::is_none"
)]
pub stack_level: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ClearChargingProfile {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.evse_id {
let p = path.field("evseId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.stack_level {
let p = path.field("stackLevel");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClearMonitoringResult {
#[serde(rename = "status")]
pub status: ClearMonitoringStatusEnum,
/// Id of the monitor of which a clear was requested.
#[serde(rename = "id")]
pub id: i64,
#[serde(
rename = "statusInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub status_info: Option<StatusInfo>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ClearMonitoringResult {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.status_info {
let p = path.field("statusInfo");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClearTariffsResult {
#[serde(
rename = "statusInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub status_info: Option<StatusInfo>,
/// Id of tariff for which _status_ is reported. If no tariffs were found, then this field is absent, and _status_ will be `NoTariff`.
#[serde(rename = "tariffId", default, skip_serializing_if = "Option::is_none")]
pub tariff_id: Option<String>,
#[serde(rename = "status")]
pub status: TariffClearStatusEnum,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ClearTariffsResult {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.status_info {
let p = path.field("statusInfo");
x.validate(&p)?;
}
if let Some(x) = &self.tariff_id {
let p = path.field("tariffId");
v::max_length(x, 60, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// A physical or logical component
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Component {
#[serde(rename = "evse", default, skip_serializing_if = "Option::is_none")]
pub evse: Option<EVSE>,
/// 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.
#[serde(rename = "name")]
pub name: String,
/// Name of instance in case the component exists as multiple instances. Case Insensitive. strongly advised to use Camel Case.
#[serde(rename = "instance", default, skip_serializing_if = "Option::is_none")]
pub instance: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Component {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.evse {
let p = path.field("evse");
x.validate(&p)?;
}
{
let x = &self.name;
let p = path.field("name");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.instance {
let p = path.field("instance");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to report components, variables and variable attributes and characteristics.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ComponentVariable {
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable", default, skip_serializing_if = "Option::is_none")]
pub variable: Option<Variable>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ComponentVariable {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
if let Some(x) = &self.variable {
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CompositeSchedule {
#[serde(rename = "evseId")]
pub evse_id: i64,
#[serde(rename = "duration")]
pub duration: i64,
#[serde(rename = "scheduleStart")]
pub schedule_start: DateTime,
#[serde(rename = "chargingRateUnit")]
pub charging_rate_unit: ChargingRateUnitEnum,
#[serde(rename = "chargingSchedulePeriod")]
pub charging_schedule_period: Vec<ChargingSchedulePeriod>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CompositeSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.evse_id;
let p = path.field("evseId");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.charging_schedule_period;
let p = path.field("chargingSchedulePeriod");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ConstantStreamData {
/// Uniquely identifies the stream
#[serde(rename = "id")]
pub id: i64,
#[serde(rename = "params")]
pub params: PeriodicEventStreamParams,
/// Id of monitor used to report his event. It can be a preconfigured or hardwired monitor.
#[serde(rename = "variableMonitoringId")]
pub variable_monitoring_id: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ConstantStreamData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.params;
let p = path.field("params");
x.validate(&p)?;
}
{
let x = &self.variable_monitoring_id;
let p = path.field("variableMonitoringId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ConsumptionCost {
/// 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.
#[serde(rename = "startValue")]
pub start_value: f64,
#[serde(rename = "cost")]
pub cost: Vec<Cost>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ConsumptionCost {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.cost;
let p = path.field("cost");
v::items(x, Some(1), Some(3), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Cost {
#[serde(rename = "costKind")]
pub cost_kind: CostKindEnum,
/// The estimated or actual cost per kWh
#[serde(rename = "amount")]
pub amount: i64,
/// Values: -3..3, The amountMultiplier defines the exponent to base 10 (dec). The final value is determined by: amount * 10 ^ amountMultiplier
#[serde(
rename = "amountMultiplier",
default,
skip_serializing_if = "Option::is_none"
)]
pub amount_multiplier: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Cost {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CostDetails {
#[serde(
rename = "chargingPeriods",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_periods: Option<Vec<ChargingPeriod>>,
#[serde(rename = "totalCost")]
pub total_cost: TotalCost,
#[serde(rename = "totalUsage")]
pub total_usage: TotalUsage,
/// If set to true, then Charging Station has failed to calculate the cost.
#[serde(
rename = "failureToCalculate",
default,
skip_serializing_if = "Option::is_none"
)]
pub failure_to_calculate: Option<bool>,
/// Optional human-readable reason text in case of failure to calculate.
#[serde(
rename = "failureReason",
default,
skip_serializing_if = "Option::is_none"
)]
pub failure_reason: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CostDetails {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.charging_periods {
let p = path.field("chargingPeriods");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
{
let x = &self.total_cost;
let p = path.field("totalCost");
x.validate(&p)?;
}
{
let x = &self.total_usage;
let p = path.field("totalUsage");
x.validate(&p)?;
}
if let Some(x) = &self.failure_reason {
let p = path.field("failureReason");
v::max_length(x, 500, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Volume consumed of cost dimension.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CostDimension {
#[serde(rename = "type")]
pub r#type: CostDimensionEnum,
/// Volume of the dimension consumed, measured according to the dimension type.
#[serde(rename = "volume")]
pub volume: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for CostDimension {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
pub struct CustomData {
#[serde(rename = "vendorId")]
pub vendor_id: String,
/// Vendor-specific properties.
#[serde(flatten)]
pub extra: serde_json::Map<String, serde_json::Value>,
}
impl Validate for CustomData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.vendor_id;
let p = path.field("vendorId");
v::max_length(x, 255, &p)?;
}
Ok(())
}
}
/// EV DC charging parameters for ISO 15118-2
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DCChargingParameters {
/// Maximum current (in A) supported by the electric vehicle. Includes cable capacity.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType:EVMaximumCurrentLimit
#[serde(rename = "evMaxCurrent")]
pub ev_max_current: f64,
/// Maximum voltage supported by the electric vehicle.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVMaximumVoltageLimit
#[serde(rename = "evMaxVoltage")]
pub ev_max_voltage: f64,
/// Maximum power (in W) supported by the electric vehicle. Required for DC charging.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVMaximumPowerLimit
#[serde(
rename = "evMaxPower",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_max_power: Option<f64>,
/// Capacity of the electric vehicle battery (in Wh).
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVEnergyCapacity
#[serde(
rename = "evEnergyCapacity",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_energy_capacity: Option<f64>,
/// Amount of energy requested (in Wh). This inludes energy required for preconditioning.
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: EVEnergyRequest
#[serde(
rename = "energyAmount",
default,
skip_serializing_if = "Option::is_none"
)]
pub energy_amount: Option<f64>,
/// Energy available in the battery (in percent of the battery capacity)
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: DC_EVStatus: EVRESSSOC
#[serde(
rename = "stateOfCharge",
default,
skip_serializing_if = "Option::is_none"
)]
pub state_of_charge: Option<i64>,
/// Percentage of SoC at which the EV considers the battery fully charged. (possible values: 0 - 100)
/// Relates to: +
/// *ISO 15118-2*: DC_EVChargeParameterType: FullSOC
#[serde(rename = "fullSoC", default, skip_serializing_if = "Option::is_none")]
pub full_so_c: Option<i64>,
/// 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
#[serde(rename = "bulkSoC", default, skip_serializing_if = "Option::is_none")]
pub bulk_so_c: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for DCChargingParameters {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.state_of_charge {
let p = path.field("stateOfCharge");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.full_so_c {
let p = path.field("fullSoC");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.bulk_so_c {
let p = path.field("bulkSoC");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(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, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DERChargingParameters {
/// DER control functions supported by EV. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType:DERControlFunctions (bitmap)
#[serde(
rename = "evSupportedDERControl",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_supported_der_control: Option<Vec<DERControlEnum>>,
/// 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
#[serde(
rename = "evOverExcitedMaxDischargePower",
default,
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
#[serde(
rename = "evOverExcitedPowerFactor",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_over_excited_power_factor: Option<f64>,
/// 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
#[serde(
rename = "evUnderExcitedMaxDischargePower",
default,
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
#[serde(
rename = "evUnderExcitedPowerFactor",
default,
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
#[serde(
rename = "maxApparentPower",
default,
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
#[serde(
rename = "maxChargeApparentPower",
default,
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
#[serde(
rename = "maxChargeApparentPower_L2",
default,
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
#[serde(
rename = "maxChargeApparentPower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_charge_apparent_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
#[serde(
rename = "maxDischargeApparentPower",
default,
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
#[serde(
rename = "maxDischargeApparentPower_L2",
default,
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
#[serde(
rename = "maxDischargeApparentPower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_discharge_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
#[serde(
rename = "maxChargeReactivePower",
default,
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
#[serde(
rename = "maxChargeReactivePower_L2",
default,
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
#[serde(
rename = "maxChargeReactivePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_charge_reactive_power_l3: 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
#[serde(
rename = "minChargeReactivePower",
default,
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
#[serde(
rename = "minChargeReactivePower_L2",
default,
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
#[serde(
rename = "minChargeReactivePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_charge_reactive_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
#[serde(
rename = "maxDischargeReactivePower",
default,
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
#[serde(
rename = "maxDischargeReactivePower_L2",
default,
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
#[serde(
rename = "maxDischargeReactivePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_discharge_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
#[serde(
rename = "minDischargeReactivePower",
default,
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
#[serde(
rename = "minDischargeReactivePower_L2",
default,
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
#[serde(
rename = "minDischargeReactivePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_discharge_reactive_power_l3: Option<f64>,
/// Line voltage supported by EVSE and EV.
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVNominalVoltage
#[serde(
rename = "nominalVoltage",
default,
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
#[serde(
rename = "nominalVoltageOffset",
default,
skip_serializing_if = "Option::is_none"
)]
pub nominal_voltage_offset: Option<f64>,
/// Maximum AC rms voltage, as defined by min(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumNominalVoltage
#[serde(
rename = "maxNominalVoltage",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_nominal_voltage: Option<f64>,
/// Minimum AC rms voltage, as defined by max(EV, EVSE) to operate with. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMinimumNominalVoltage
#[serde(
rename = "minNominalVoltage",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_nominal_voltage: Option<f64>,
/// Manufacturer of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterManufacturer
#[serde(
rename = "evInverterManufacturer",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_inverter_manufacturer: Option<String>,
/// Model name of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterModel
#[serde(
rename = "evInverterModel",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_inverter_model: Option<String>,
/// Serial number of the EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSerialNumber
#[serde(
rename = "evInverterSerialNumber",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_inverter_serial_number: Option<String>,
/// Software version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterSwVersion
#[serde(
rename = "evInverterSwVersion",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_inverter_sw_version: Option<String>,
/// Hardware version of EV inverter. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVInverterHwVersion
#[serde(
rename = "evInverterHwVersion",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_inverter_hw_version: Option<String>,
/// 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
#[serde(
rename = "evIslandingDetectionMethod",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_islanding_detection_method: Option<Vec<IslandingDetectionEnum>>,
/// Time after which EV will trip if an island has been detected. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVIslandingTripTime
#[serde(
rename = "evIslandingTripTime",
default,
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
#[serde(
rename = "evMaximumLevel1DCInjection",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_maximum_level1_dc_injection: Option<f64>,
/// Maximum allowed duration of DC injection at level 1 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel1DCInjection
#[serde(
rename = "evDurationLevel1DCInjection",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_duration_level1_dc_injection: Option<f64>,
/// Maximum injected DC current allowed at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVMaximumLevel2DCInjection
#[serde(
rename = "evMaximumLevel2DCInjection",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_maximum_level2_dc_injection: Option<f64>,
/// Maximum allowed duration of DC injection at level 2 charging. +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVDurationLevel2DCInjection
#[serde(
rename = "evDurationLevel2DCInjection",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_duration_level2_dc_injection: Option<f64>,
/// Measure of the susceptibility of the circuit to reactance, in Siemens (S). +
/// *ISO 15118-20*: DER_BPT_AC_CPDReqEnergyTransferModeType: EVReactiveSusceptance
#[serde(
rename = "evReactiveSusceptance",
default,
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
#[serde(
rename = "evSessionTotalDischargeEnergyAvailable",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_session_total_discharge_energy_available: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for DERChargingParameters {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.ev_supported_der_control {
let p = path.field("evSupportedDERControl");
v::items(x, Some(1), None, &p)?;
}
if let Some(x) = &self.ev_inverter_manufacturer {
let p = path.field("evInverterManufacturer");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.ev_inverter_model {
let p = path.field("evInverterModel");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.ev_inverter_serial_number {
let p = path.field("evInverterSerialNumber");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.ev_inverter_sw_version {
let p = path.field("evInverterSwVersion");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.ev_inverter_hw_version {
let p = path.field("evInverterHwVersion");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.ev_islanding_detection_method {
let p = path.field("evIslandingDetectionMethod");
v::items(x, Some(1), None, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DERCurve {
#[serde(rename = "curveData")]
pub curve_data: Vec<DERCurvePoints>,
#[serde(
rename = "hysteresis",
default,
skip_serializing_if = "Option::is_none"
)]
pub hysteresis: Option<Hysteresis>,
/// Priority of curve (0=highest)
#[serde(rename = "priority")]
pub priority: i64,
#[serde(
rename = "reactivePowerParams",
default,
skip_serializing_if = "Option::is_none"
)]
pub reactive_power_params: Option<ReactivePowerParams>,
#[serde(
rename = "voltageParams",
default,
skip_serializing_if = "Option::is_none"
)]
pub voltage_params: Option<VoltageParams>,
#[serde(rename = "yUnit")]
pub y_unit: DERUnitEnum,
/// 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.
#[serde(
rename = "responseTime",
default,
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.
#[serde(rename = "startTime", default, skip_serializing_if = "Option::is_none")]
pub start_time: Option<DateTime>,
/// Duration in seconds that this curve will be active. Only absent when _default_ is true.
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for DERCurve {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.curve_data;
let p = path.field("curveData");
v::items(x, Some(1), Some(10), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.hysteresis {
let p = path.field("hysteresis");
x.validate(&p)?;
}
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.reactive_power_params {
let p = path.field("reactivePowerParams");
x.validate(&p)?;
}
if let Some(x) = &self.voltage_params {
let p = path.field("voltageParams");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DERCurveGet {
#[serde(rename = "curve")]
pub curve: DERCurve,
/// Id of DER curve
#[serde(rename = "id")]
pub id: String,
#[serde(rename = "curveType")]
pub curve_type: DERControlEnum,
/// True if this is a default curve
#[serde(rename = "isDefault")]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[serde(rename = "isSuperseded")]
pub is_superseded: bool,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for DERCurveGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.curve;
let p = path.field("curve");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DERCurvePoints {
/// The data value of the X-axis (independent) variable, depending on the curve type.
#[serde(rename = "x")]
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).
#[serde(rename = "y")]
pub y: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for DERCurvePoints {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* Price schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVAbsolutePriceSchedule {
/// Starting point in time of the EVEnergyOffer.
#[serde(rename = "timeAnchor")]
pub time_anchor: DateTime,
/// Currency code according to ISO 4217.
#[serde(rename = "currency")]
pub currency: String,
#[serde(rename = "evAbsolutePriceScheduleEntries")]
pub ev_absolute_price_schedule_entries: Vec<EVAbsolutePriceScheduleEntry>,
/// ISO 15118-20 URN of price algorithm: Power, PeakPower, StackedEnergy.
#[serde(rename = "priceAlgorithm")]
pub price_algorithm: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVAbsolutePriceSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.currency;
let p = path.field("currency");
v::max_length(x, 3, &p)?;
}
{
let x = &self.ev_absolute_price_schedule_entries;
let p = path.field("evAbsolutePriceScheduleEntries");
v::items(x, Some(1), Some(1024), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
{
let x = &self.price_algorithm;
let p = path.field("priceAlgorithm");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* An entry in price schedule over time for which EV is willing to discharge.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVAbsolutePriceScheduleEntry {
/// The amount of seconds of this entry.
#[serde(rename = "duration")]
pub duration: i64,
#[serde(rename = "evPriceRule")]
pub ev_price_rule: Vec<EVPriceRule>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVAbsolutePriceScheduleEntry {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.ev_price_rule;
let p = path.field("evPriceRule");
v::items(x, Some(1), Some(8), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVEnergyOffer {
#[serde(
rename = "evAbsolutePriceSchedule",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_absolute_price_schedule: Option<EVAbsolutePriceSchedule>,
#[serde(rename = "evPowerSchedule")]
pub ev_power_schedule: EVPowerSchedule,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVEnergyOffer {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.ev_absolute_price_schedule {
let p = path.field("evAbsolutePriceSchedule");
x.validate(&p)?;
}
{
let x = &self.ev_power_schedule;
let p = path.field("evPowerSchedule");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* Schedule of EV energy offer.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVPowerSchedule {
#[serde(rename = "evPowerScheduleEntries")]
pub ev_power_schedule_entries: Vec<EVPowerScheduleEntry>,
/// The time that defines the starting point for the EVEnergyOffer.
#[serde(rename = "timeAnchor")]
pub time_anchor: DateTime,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVPowerSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.ev_power_schedule_entries;
let p = path.field("evPowerScheduleEntries");
v::items(x, Some(1), Some(1024), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVPowerScheduleEntry {
/// The duration of this entry.
#[serde(rename = "duration")]
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.
#[serde(rename = "power")]
pub power: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVPowerScheduleEntry {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* An entry in price schedule over time for which EV is willing to discharge.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVPriceRule {
/// Cost per kWh.
#[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.
#[serde(rename = "powerRangeStart")]
pub power_range_start: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVPriceRule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Electric Vehicle Supply Equipment
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EVSE {
/// EVSE Identifier. This contains a number (> 0) designating an EVSE of the Charging Station.
#[serde(rename = "id")]
pub id: i64,
/// An id to designate a specific connector (on an EVSE) by connector index number.
#[serde(
rename = "connectorId",
default,
skip_serializing_if = "Option::is_none"
)]
pub connector_id: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EVSE {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.connector_id {
let p = path.field("connectorId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EnterService {
/// Priority of setting (0=highest)
#[serde(rename = "priority")]
pub priority: i64,
/// Enter service voltage high
#[serde(rename = "highVoltage")]
pub high_voltage: f64,
/// Enter service voltage low
#[serde(rename = "lowVoltage")]
pub low_voltage: f64,
/// Enter service frequency high
#[serde(rename = "highFreq")]
pub high_freq: f64,
/// Enter service frequency low
#[serde(rename = "lowFreq")]
pub low_freq: f64,
/// Enter service delay
#[serde(rename = "delay", default, skip_serializing_if = "Option::is_none")]
pub delay: Option<f64>,
/// Enter service randomized delay
#[serde(
rename = "randomDelay",
default,
skip_serializing_if = "Option::is_none"
)]
pub random_delay: Option<f64>,
/// Enter service ramp rate in seconds
#[serde(rename = "rampRate", default, skip_serializing_if = "Option::is_none")]
pub ramp_rate: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EnterService {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EnterServiceGet {
#[serde(rename = "enterService")]
pub enter_service: EnterService,
/// Id of setting
#[serde(rename = "id")]
pub id: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EnterServiceGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.enter_service;
let p = path.field("enterService");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to report an event notification for a component-variable.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EventData {
/// Identifies the event. This field can be referred to as a cause by other events.
#[serde(rename = "eventId")]
pub event_id: i64,
/// Timestamp of the moment the report was generated.
#[serde(rename = "timestamp")]
pub timestamp: DateTime,
#[serde(rename = "trigger")]
pub trigger: EventTriggerEnum,
/// Refers to the Id of an event that is considered to be the cause for this event.
#[serde(rename = "cause", default, skip_serializing_if = "Option::is_none")]
pub cause: Option<i64>,
/// 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.
#[serde(rename = "actualValue")]
pub actual_value: String,
/// Technical (error) code as reported by component.
#[serde(rename = "techCode", default, skip_serializing_if = "Option::is_none")]
pub tech_code: Option<String>,
/// Technical detail information as reported by component.
#[serde(rename = "techInfo", default, skip_serializing_if = "Option::is_none")]
pub tech_info: Option<String>,
/// _Cleared_ is set to true to report the clearing of a monitored situation, i.e. a 'return to normal'.
#[serde(rename = "cleared", default, skip_serializing_if = "Option::is_none")]
pub cleared: Option<bool>,
/// If an event notification is linked to a specific transaction, this field can be used to specify its transactionId.
#[serde(
rename = "transactionId",
default,
skip_serializing_if = "Option::is_none"
)]
pub transaction_id: Option<String>,
#[serde(rename = "component")]
pub component: Component,
/// Identifies the VariableMonitoring which triggered the event.
#[serde(
rename = "variableMonitoringId",
default,
skip_serializing_if = "Option::is_none"
)]
pub variable_monitoring_id: Option<i64>,
#[serde(rename = "eventNotificationType")]
pub event_notification_type: EventNotificationEnum,
#[serde(rename = "variable")]
pub variable: Variable,
/// *(2.1)* Severity associated with the monitor in _variableMonitoringId_ or with the hardwired notification.
#[serde(rename = "severity", default, skip_serializing_if = "Option::is_none")]
pub severity: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for EventData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.event_id;
let p = path.field("eventId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.cause {
let p = path.field("cause");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.actual_value;
let p = path.field("actualValue");
v::max_length(x, 2500, &p)?;
}
if let Some(x) = &self.tech_code {
let p = path.field("techCode");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.tech_info {
let p = path.field("techInfo");
v::max_length(x, 500, &p)?;
}
if let Some(x) = &self.transaction_id {
let p = path.field("transactionId");
v::max_length(x, 36, &p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
if let Some(x) = &self.variable_monitoring_id {
let p = path.field("variableMonitoringId");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.severity {
let p = path.field("severity");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Represents a copy of the firmware that can be loaded/updated on the Charging Station.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Firmware {
/// URI defining the origin of the firmware.
#[serde(rename = "location")]
pub location: String,
/// Date and time at which the firmware shall be retrieved.
#[serde(rename = "retrieveDateTime")]
pub retrieve_date_time: DateTime,
/// Date and time at which the firmware shall be installed.
#[serde(
rename = "installDateTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub install_date_time: Option<DateTime>,
/// Certificate with which the firmware was signed.
/// PEM encoded X.509 certificate.
#[serde(
rename = "signingCertificate",
default,
skip_serializing_if = "Option::is_none"
)]
pub signing_certificate: Option<String>,
/// Base64 encoded firmware signature.
#[serde(rename = "signature", default, skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Firmware {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.location;
let p = path.field("location");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.signing_certificate {
let p = path.field("signingCertificate");
v::max_length(x, 5500, &p)?;
}
if let Some(x) = &self.signature {
let p = path.field("signature");
v::max_length(x, 800, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FixedPF {
/// Priority of setting (0=highest)
#[serde(rename = "priority")]
pub priority: i64,
/// Power factor, cos(phi), as value between 0..1.
#[serde(rename = "displacement")]
pub displacement: f64,
/// True when absorbing reactive power (under-excited), false when injecting reactive power (over-excited).
#[serde(rename = "excitation")]
pub excitation: bool,
/// Time when this setting becomes active
#[serde(rename = "startTime", default, skip_serializing_if = "Option::is_none")]
pub start_time: Option<DateTime>,
/// Duration in seconds that this setting is active.
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FixedPF {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FixedPFGet {
#[serde(rename = "fixedPF")]
pub fixed_pf: FixedPF,
/// Id of setting.
#[serde(rename = "id")]
pub id: String,
/// True if setting is a default control.
#[serde(rename = "isDefault")]
pub is_default: bool,
/// True if this setting is superseded by a lower priority setting.
#[serde(rename = "isSuperseded")]
pub is_superseded: bool,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FixedPFGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.fixed_pf;
let p = path.field("fixedPF");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FixedVar {
/// Priority of setting (0=highest)
#[serde(rename = "priority")]
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.
#[serde(rename = "setpoint")]
pub setpoint: f64,
#[serde(rename = "unit")]
pub unit: DERUnitEnum,
/// Time when this setting becomes active.
#[serde(rename = "startTime", default, skip_serializing_if = "Option::is_none")]
pub start_time: Option<DateTime>,
/// Duration in seconds that this setting is active.
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FixedVar {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FixedVarGet {
#[serde(rename = "fixedVar")]
pub fixed_var: FixedVar,
/// Id of setting
#[serde(rename = "id")]
pub id: String,
/// True if setting is a default control.
#[serde(rename = "isDefault")]
pub is_default: bool,
/// True if this setting is superseded by a lower priority setting
#[serde(rename = "isSuperseded")]
pub is_superseded: bool,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FixedVarGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.fixed_var;
let p = path.field("fixedVar");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FreqDroop {
/// Priority of setting (0=highest)
#[serde(rename = "priority")]
pub priority: i64,
/// Over-frequency start of droop
#[serde(rename = "overFreq")]
pub over_freq: f64,
/// Under-frequency start of droop
#[serde(rename = "underFreq")]
pub under_freq: f64,
/// Over-frequency droop per unit, oFDroop
#[serde(rename = "overDroop")]
pub over_droop: f64,
/// Under-frequency droop per unit, uFDroop
#[serde(rename = "underDroop")]
pub under_droop: f64,
/// Open loop response time in seconds
#[serde(rename = "responseTime")]
pub response_time: f64,
/// Time when this setting becomes active
#[serde(rename = "startTime", default, skip_serializing_if = "Option::is_none")]
pub start_time: Option<DateTime>,
/// Duration in seconds that this setting is active
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FreqDroop {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FreqDroopGet {
#[serde(rename = "freqDroop")]
pub freq_droop: FreqDroop,
/// Id of setting
#[serde(rename = "id")]
pub id: String,
/// True if setting is a default control.
#[serde(rename = "isDefault")]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[serde(rename = "isSuperseded")]
pub is_superseded: bool,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for FreqDroopGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.freq_droop;
let p = path.field("freqDroop");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to hold parameters for GetVariables request.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GetVariableData {
#[serde(
rename = "attributeType",
default,
skip_serializing_if = "Option::is_none"
)]
pub attribute_type: Option<AttributeEnum>,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for GetVariableData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to hold results of GetVariables request.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GetVariableResult {
#[serde(rename = "attributeStatus")]
pub attribute_status: GetVariableStatusEnum,
#[serde(
rename = "attributeStatusInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub attribute_status_info: Option<StatusInfo>,
#[serde(
rename = "attributeType",
default,
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.
#[serde(
rename = "attributeValue",
default,
skip_serializing_if = "Option::is_none"
)]
pub attribute_value: Option<String>,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for GetVariableResult {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.attribute_status_info {
let p = path.field("attributeStatusInfo");
x.validate(&p)?;
}
if let Some(x) = &self.attribute_value {
let p = path.field("attributeValue");
v::max_length(x, 2500, &p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Gradient {
/// Id of setting
#[serde(rename = "priority")]
pub priority: i64,
/// Default ramp rate in seconds (0 if not applicable)
#[serde(rename = "gradient")]
pub gradient: f64,
/// Soft-start ramp rate in seconds (0 if not applicable)
#[serde(rename = "softGradient")]
pub soft_gradient: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Gradient {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GradientGet {
#[serde(rename = "gradient")]
pub gradient: Gradient,
/// Id of setting
#[serde(rename = "id")]
pub id: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for GradientGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.gradient;
let p = path.field("gradient");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Hysteresis {
/// High value for return to normal operation after a grid event, in absolute value. This value adopts the same unit as defined by yUnit
#[serde(
rename = "hysteresisHigh",
default,
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
#[serde(
rename = "hysteresisLow",
default,
skip_serializing_if = "Option::is_none"
)]
pub hysteresis_low: Option<f64>,
/// Delay in seconds, once grid parameter within HysteresisLow and HysteresisHigh, for the EV to return to normal operation after a grid event.
#[serde(
rename = "hysteresisDelay",
default,
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
#[serde(
rename = "hysteresisGradient",
default,
skip_serializing_if = "Option::is_none"
)]
pub hysteresis_gradient: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Hysteresis {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct IdToken {
#[serde(
rename = "additionalInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub additional_info: Option<Vec<AdditionalInfo>>,
/// *(2.1)* IdToken is case insensitive. Might hold the hidden id of an RFID tag, but can for example also contain a UUID.
#[serde(rename = "idToken")]
pub id_token: String,
/// *(2.1)* Enumeration of possible idToken types. Values defined in Appendix as IdTokenEnumStringType.
#[serde(rename = "type")]
pub r#type: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for IdToken {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.additional_info {
let p = path.field("additionalInfo");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
{
let x = &self.id_token;
let p = path.field("idToken");
v::max_length(x, 255, &p)?;
}
{
let x = &self.r#type;
let p = path.field("type");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct IdTokenInfo {
#[serde(rename = "status")]
pub status: AuthorizationStatusEnum,
/// Date and Time after which the token must be considered invalid.
#[serde(
rename = "cacheExpiryDateTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub cache_expiry_date_time: Option<DateTime>,
/// 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.
#[serde(
rename = "chargingPriority",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_priority: Option<i64>,
#[serde(
rename = "groupIdToken",
default,
skip_serializing_if = "Option::is_none"
)]
pub group_id_token: Option<IdToken>,
/// Preferred user interface language of identifier user. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[serde(rename = "language1", default, skip_serializing_if = "Option::is_none")]
pub language1: Option<String>,
/// 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\]>>.
#[serde(rename = "language2", default, skip_serializing_if = "Option::is_none")]
pub language2: Option<String>,
/// Only used when the IdToken is only valid for one or more specific EVSEs, not for the entire Charging Station.
#[serde(rename = "evseId", default, skip_serializing_if = "Option::is_none")]
pub evse_id: Option<Vec<i64>>,
#[serde(
rename = "personalMessage",
default,
skip_serializing_if = "Option::is_none"
)]
pub personal_message: Option<MessageContent>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for IdTokenInfo {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.group_id_token {
let p = path.field("groupIdToken");
x.validate(&p)?;
}
if let Some(x) = &self.language1 {
let p = path.field("language1");
v::max_length(x, 8, &p)?;
}
if let Some(x) = &self.language2 {
let p = path.field("language2");
v::max_length(x, 8, &p)?;
}
if let Some(x) = &self.evse_id {
let p = path.field("evseId");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
v::minimum(*it0, 0i64, &p0)?;
}
}
if let Some(x) = &self.personal_message {
let p = path.field("personalMessage");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LimitAtSoC {
/// The SoC value beyond which the charging rate limit should be applied.
#[serde(rename = "soc")]
pub soc: i64,
/// Charging rate limit beyond the SoC value.
/// The unit is defined by _chargingSchedule.chargingRateUnit_.
#[serde(rename = "limit")]
pub limit: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for LimitAtSoC {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.soc;
let p = path.field("soc");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LimitMaxDischarge {
/// Priority of setting (0=highest)
#[serde(rename = "priority")]
pub priority: i64,
/// 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.
#[serde(
rename = "pctMaxDischargePower",
default,
skip_serializing_if = "Option::is_none"
)]
pub pct_max_discharge_power: Option<f64>,
#[serde(
rename = "powerMonitoringMustTrip",
default,
skip_serializing_if = "Option::is_none"
)]
pub power_monitoring_must_trip: Option<DERCurve>,
/// Time when this setting becomes active
#[serde(rename = "startTime", default, skip_serializing_if = "Option::is_none")]
pub start_time: Option<DateTime>,
/// Duration in seconds that this setting is active
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for LimitMaxDischarge {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.priority;
let p = path.field("priority");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.power_monitoring_must_trip {
let p = path.field("powerMonitoringMustTrip");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LimitMaxDischargeGet {
/// Id of setting
#[serde(rename = "id")]
pub id: String,
/// True if setting is a default control.
#[serde(rename = "isDefault")]
pub is_default: bool,
/// True if this setting is superseded by a higher priority setting (i.e. lower value of _priority_)
#[serde(rename = "isSuperseded")]
pub is_superseded: bool,
#[serde(rename = "limitMaxDischarge")]
pub limit_max_discharge: LimitMaxDischarge,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for LimitMaxDischargeGet {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::max_length(x, 36, &p)?;
}
{
let x = &self.limit_max_discharge;
let p = path.field("limitMaxDischarge");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Generic class for the configuration of logging entries.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LogParameters {
/// The URL of the location at the remote system where the log should be stored.
#[serde(rename = "remoteLocation")]
pub remote_location: String,
/// This contains the date and time of the oldest logging information to include in the diagnostics.
#[serde(
rename = "oldestTimestamp",
default,
skip_serializing_if = "Option::is_none"
)]
pub oldest_timestamp: Option<DateTime>,
/// This contains the date and time of the latest logging information to include in the diagnostics.
#[serde(
rename = "latestTimestamp",
default,
skip_serializing_if = "Option::is_none"
)]
pub latest_timestamp: Option<DateTime>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for LogParameters {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.remote_location;
let p = path.field("remoteLocation");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MessageContent {
#[serde(rename = "format")]
pub format: MessageFormatEnum,
/// Message language identifier. Contains a language code as defined in <<ref-RFC5646,\[RFC5646\]>>.
#[serde(rename = "language", default, skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
/// *(2.1)* Required. Message contents. +
/// Maximum length supported by Charging Station is given in OCPPCommCtrlr.FieldLength\["MessageContentType.content"\].
/// Maximum length defaults to 1024.
#[serde(rename = "content")]
pub content: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for MessageContent {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.language {
let p = path.field("language");
v::max_length(x, 8, &p)?;
}
{
let x = &self.content;
let p = path.field("content");
v::max_length(x, 1024, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Contains message details, for a message to be displayed on a Charging Station.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MessageInfo {
#[serde(rename = "display", default, skip_serializing_if = "Option::is_none")]
pub display: Option<Component>,
/// Unique id within an exchange context. It is defined within the OCPP context as a positive Integer value (greater or equal to zero).
#[serde(rename = "id")]
pub id: i64,
#[serde(rename = "priority")]
pub priority: MessagePriorityEnum,
#[serde(rename = "state", default, skip_serializing_if = "Option::is_none")]
pub state: Option<MessageStateEnum>,
/// From what date-time should this message be shown. If omitted: directly.
#[serde(
rename = "startDateTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub start_date_time: Option<DateTime>,
/// Until what date-time should this message be shown, after this date/time this message SHALL be removed.
#[serde(
rename = "endDateTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub end_date_time: Option<DateTime>,
/// During which transaction shall this message be shown.
/// Message SHALL be removed by the Charging Station after transaction has
/// ended.
#[serde(
rename = "transactionId",
default,
skip_serializing_if = "Option::is_none"
)]
pub transaction_id: Option<String>,
#[serde(rename = "message")]
pub message: MessageContent,
#[serde(
rename = "messageExtra",
default,
skip_serializing_if = "Option::is_none"
)]
pub message_extra: Option<Vec<MessageContent>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for MessageInfo {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.display {
let p = path.field("display");
x.validate(&p)?;
}
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.transaction_id {
let p = path.field("transactionId");
v::max_length(x, 36, &p)?;
}
{
let x = &self.message;
let p = path.field("message");
x.validate(&p)?;
}
if let Some(x) = &self.message_extra {
let p = path.field("messageExtra");
v::items(x, Some(1), Some(4), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MeterValue {
#[serde(rename = "sampledValue")]
pub sampled_value: Vec<SampledValue>,
/// Timestamp for measured value(s).
#[serde(rename = "timestamp")]
pub timestamp: DateTime,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for MeterValue {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.sampled_value;
let p = path.field("sampledValue");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Defines parameters required for initiating and maintaining wireless communication with other devices.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Modem {
/// This contains the ICCID of the modem’s SIM card.
#[serde(rename = "iccid", default, skip_serializing_if = "Option::is_none")]
pub iccid: Option<String>,
/// This contains the IMSI of the modem’s SIM card.
#[serde(rename = "imsi", default, skip_serializing_if = "Option::is_none")]
pub imsi: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Modem {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.iccid {
let p = path.field("iccid");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.imsi {
let p = path.field("imsi");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to hold parameters of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MonitoringData {
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(rename = "variableMonitoring")]
pub variable_monitoring: Vec<VariableMonitoring>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for MonitoringData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
{
let x = &self.variable_monitoring;
let p = path.field("variableMonitoring");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// The NetworkConnectionProfile defines the functional and technical parameters of a communication link.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NetworkConnectionProfile {
#[serde(rename = "apn", default, skip_serializing_if = "Option::is_none")]
pub apn: Option<APN>,
#[serde(
rename = "ocppVersion",
default,
skip_serializing_if = "Option::is_none"
)]
pub ocpp_version: Option<OCPPVersionEnum>,
#[serde(rename = "ocppInterface")]
pub ocpp_interface: OCPPInterfaceEnum,
#[serde(rename = "ocppTransport")]
pub ocpp_transport: OCPPTransportEnum,
/// 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.
#[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.
#[serde(rename = "ocppCsmsUrl")]
pub ocpp_csms_url: String,
/// This field specifies the security profile used when connecting to the CSMS with this NetworkConnectionProfile.
#[serde(rename = "securityProfile")]
pub security_profile: i64,
/// *(2.1)* Charging Station identity to be used as the basic authentication username.
#[serde(rename = "identity", default, skip_serializing_if = "Option::is_none")]
pub identity: Option<String>,
/// *(2.1)* BasicAuthPassword to use for security profile 1 or 2.
#[serde(
rename = "basicAuthPassword",
default,
skip_serializing_if = "Option::is_none"
)]
pub basic_auth_password: Option<String>,
#[serde(rename = "vpn", default, skip_serializing_if = "Option::is_none")]
pub vpn: Option<VPN>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for NetworkConnectionProfile {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.apn {
let p = path.field("apn");
x.validate(&p)?;
}
{
let x = &self.ocpp_csms_url;
let p = path.field("ocppCsmsUrl");
v::max_length(x, 2000, &p)?;
}
{
let x = &self.security_profile;
let p = path.field("securityProfile");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.identity {
let p = path.field("identity");
v::max_length(x, 48, &p)?;
}
if let Some(x) = &self.basic_auth_password {
let p = path.field("basicAuthPassword");
v::max_length(x, 64, &p)?;
}
if let Some(x) = &self.vpn {
let p = path.field("vpn");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Information about a certificate for an OCSP check.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct OCSPRequestData {
#[serde(rename = "hashAlgorithm")]
pub hash_algorithm: HashAlgorithmEnum,
/// 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.
#[serde(rename = "issuerNameHash")]
pub issuer_name_hash: String,
/// 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.
#[serde(rename = "issuerKeyHash")]
pub issuer_key_hash: String,
/// The string representation of the
/// hexadecimal value of the serial number without the
/// prefix "0x" and without leading zeroes.
#[serde(rename = "serialNumber")]
pub serial_number: String,
/// This contains the responder URL (Case insensitive).
#[serde(rename = "responderURL")]
pub responder_url: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for OCSPRequestData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.issuer_name_hash;
let p = path.field("issuerNameHash");
v::max_length(x, 128, &p)?;
}
{
let x = &self.issuer_key_hash;
let p = path.field("issuerKeyHash");
v::max_length(x, 128, &p)?;
}
{
let x = &self.serial_number;
let p = path.field("serialNumber");
v::max_length(x, 40, &p)?;
}
{
let x = &self.responder_url;
let p = path.field("responderURL");
v::max_length(x, 2000, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct OverstayRule {
#[serde(rename = "overstayFee")]
pub overstay_fee: RationalNumber,
/// Human readable string to identify the overstay rule.
#[serde(
rename = "overstayRuleDescription",
default,
skip_serializing_if = "Option::is_none"
)]
pub overstay_rule_description: Option<String>,
/// Time in seconds after trigger of the parent Overstay Rules for this particular fee to apply.
#[serde(rename = "startTime")]
pub start_time: i64,
/// Time till overstay will be reapplied
#[serde(rename = "overstayFeePeriod")]
pub overstay_fee_period: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for OverstayRule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.overstay_fee;
let p = path.field("overstayFee");
x.validate(&p)?;
}
if let Some(x) = &self.overstay_rule_description {
let p = path.field("overstayRuleDescription");
v::max_length(x, 32, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct OverstayRuleList {
#[serde(
rename = "overstayPowerThreshold",
default,
skip_serializing_if = "Option::is_none"
)]
pub overstay_power_threshold: Option<RationalNumber>,
#[serde(rename = "overstayRule")]
pub overstay_rule: Vec<OverstayRule>,
/// Time till overstay is applied in seconds.
#[serde(
rename = "overstayTimeThreshold",
default,
skip_serializing_if = "Option::is_none"
)]
pub overstay_time_threshold: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for OverstayRuleList {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.overstay_power_threshold {
let p = path.field("overstayPowerThreshold");
x.validate(&p)?;
}
{
let x = &self.overstay_rule;
let p = path.field("overstayRule");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PeriodicEventStreamParams {
/// Time in seconds after which stream data is sent.
#[serde(rename = "interval", default, skip_serializing_if = "Option::is_none")]
pub interval: Option<i64>,
/// Number of items to be sent together in stream.
#[serde(rename = "values", default, skip_serializing_if = "Option::is_none")]
pub values: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for PeriodicEventStreamParams {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.interval {
let p = path.field("interval");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.values {
let p = path.field("values");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Price with and without tax. At least one of _exclTax_, _inclTax_ must be present.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Price {
/// Price/cost excluding tax. Can be absent if _inclTax_ is present.
#[serde(rename = "exclTax", default, skip_serializing_if = "Option::is_none")]
pub excl_tax: Option<f64>,
/// Price/cost including tax. Can be absent if _exclTax_ is present.
#[serde(rename = "inclTax", default, skip_serializing_if = "Option::is_none")]
pub incl_tax: Option<f64>,
#[serde(rename = "taxRates", default, skip_serializing_if = "Option::is_none")]
pub tax_rates: Option<Vec<TaxRate>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Price {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.tax_rates {
let p = path.field("taxRates");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PriceLevelSchedule {
#[serde(rename = "priceLevelScheduleEntries")]
pub price_level_schedule_entries: Vec<PriceLevelScheduleEntry>,
/// Starting point of this price schedule.
#[serde(rename = "timeAnchor")]
pub time_anchor: DateTime,
/// Unique ID of this price schedule.
#[serde(rename = "priceScheduleId")]
pub price_schedule_id: i64,
/// Description of the price schedule.
#[serde(
rename = "priceScheduleDescription",
default,
skip_serializing_if = "Option::is_none"
)]
pub price_schedule_description: Option<String>,
/// Defines the overall number of distinct price level elements used across all PriceLevelSchedules.
#[serde(rename = "numberOfPriceLevels")]
pub number_of_price_levels: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for PriceLevelSchedule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.price_level_schedule_entries;
let p = path.field("priceLevelScheduleEntries");
v::items(x, Some(1), Some(100), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
{
let x = &self.price_schedule_id;
let p = path.field("priceScheduleId");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.price_schedule_description {
let p = path.field("priceScheduleDescription");
v::max_length(x, 32, &p)?;
}
{
let x = &self.number_of_price_levels;
let p = path.field("numberOfPriceLevels");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PriceLevelScheduleEntry {
/// The amount of seconds that define the duration of this given PriceLevelScheduleEntry.
#[serde(rename = "duration")]
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.
#[serde(rename = "priceLevel")]
pub price_level: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for PriceLevelScheduleEntry {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.price_level;
let p = path.field("priceLevel");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PriceRule {
/// The duration of the parking fee period (in seconds).
/// When the time enters into a ParkingFeePeriod, the ParkingFee will apply to the session. .
#[serde(
rename = "parkingFeePeriod",
default,
skip_serializing_if = "Option::is_none"
)]
pub parking_fee_period: Option<i64>,
/// Number of grams of CO2 per kWh.
#[serde(
rename = "carbonDioxideEmission",
default,
skip_serializing_if = "Option::is_none"
)]
pub carbon_dioxide_emission: Option<i64>,
/// Percentage of the power that is created by renewable resources.
#[serde(
rename = "renewableGenerationPercentage",
default,
skip_serializing_if = "Option::is_none"
)]
pub renewable_generation_percentage: Option<i64>,
#[serde(rename = "energyFee")]
pub energy_fee: RationalNumber,
#[serde(
rename = "parkingFee",
default,
skip_serializing_if = "Option::is_none"
)]
pub parking_fee: Option<RationalNumber>,
#[serde(rename = "powerRangeStart")]
pub power_range_start: RationalNumber,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for PriceRule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.carbon_dioxide_emission {
let p = path.field("carbonDioxideEmission");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.renewable_generation_percentage {
let p = path.field("renewableGenerationPercentage");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
{
let x = &self.energy_fee;
let p = path.field("energyFee");
x.validate(&p)?;
}
if let Some(x) = &self.parking_fee {
let p = path.field("parkingFee");
x.validate(&p)?;
}
{
let x = &self.power_range_start;
let p = path.field("powerRangeStart");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PriceRuleStack {
/// Duration of the stack of price rules. he amount of seconds that define the duration of the given PriceRule(s).
#[serde(rename = "duration")]
pub duration: i64,
#[serde(rename = "priceRule")]
pub price_rule: Vec<PriceRule>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for PriceRuleStack {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.price_rule;
let p = path.field("priceRule");
v::items(x, Some(1), Some(8), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RationalNumber {
/// The exponent to base 10 (dec)
#[serde(rename = "exponent")]
pub exponent: i64,
/// Value which shall be multiplied.
#[serde(rename = "value")]
pub value: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for RationalNumber {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReactivePowerParams {
/// Only for VoltVar curve: The nominal ac voltage (rms) adjustment to the voltage curve points for Volt-Var curves (percentage).
#[serde(rename = "vRef", default, skip_serializing_if = "Option::is_none")]
pub v_ref: Option<f64>,
/// Only for VoltVar: Enable/disable autonomous VRef adjustment
#[serde(
rename = "autonomousVRefEnable",
default,
skip_serializing_if = "Option::is_none"
)]
pub autonomous_v_ref_enable: Option<bool>,
/// Only for VoltVar: Adjustment range for VRef time constant
#[serde(
rename = "autonomousVRefTimeConstant",
default,
skip_serializing_if = "Option::is_none"
)]
pub autonomous_v_ref_time_constant: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ReactivePowerParams {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RelativeTimeInterval {
/// Start of the interval, in seconds from NOW.
#[serde(rename = "start")]
pub start: i64,
/// Duration of the interval, in seconds.
#[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
pub duration: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for RelativeTimeInterval {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to report components, variables and variable attributes and characteristics.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReportData {
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(rename = "variableAttribute")]
pub variable_attribute: Vec<VariableAttribute>,
#[serde(
rename = "variableCharacteristics",
default,
skip_serializing_if = "Option::is_none"
)]
pub variable_characteristics: Option<VariableCharacteristics>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for ReportData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
{
let x = &self.variable_attribute;
let p = path.field("variableAttribute");
v::items(x, Some(1), Some(4), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.variable_characteristics {
let p = path.field("variableCharacteristics");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SalesTariff {
/// SalesTariff identifier used to identify one sales tariff. An SAID remains a unique identifier for one schedule throughout a charging session.
#[serde(rename = "id")]
pub id: i64,
/// A human readable title/short description of the sales tariff e.g. for HMI display purposes.
#[serde(
rename = "salesTariffDescription",
default,
skip_serializing_if = "Option::is_none"
)]
pub sales_tariff_description: Option<String>,
/// Defines the overall number of distinct price levels used across all provided SalesTariff elements.
#[serde(
rename = "numEPriceLevels",
default,
skip_serializing_if = "Option::is_none"
)]
pub num_e_price_levels: Option<i64>,
#[serde(rename = "salesTariffEntry")]
pub sales_tariff_entry: Vec<SalesTariffEntry>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SalesTariff {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.sales_tariff_description {
let p = path.field("salesTariffDescription");
v::max_length(x, 32, &p)?;
}
if let Some(x) = &self.num_e_price_levels {
let p = path.field("numEPriceLevels");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.sales_tariff_entry;
let p = path.field("salesTariffEntry");
v::items(x, Some(1), Some(1024), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SalesTariffEntry {
#[serde(rename = "relativeTimeInterval")]
pub relative_time_interval: RelativeTimeInterval,
/// 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.
#[serde(
rename = "ePriceLevel",
default,
skip_serializing_if = "Option::is_none"
)]
pub e_price_level: Option<i64>,
#[serde(
rename = "consumptionCost",
default,
skip_serializing_if = "Option::is_none"
)]
pub consumption_cost: Option<Vec<ConsumptionCost>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SalesTariffEntry {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.relative_time_interval;
let p = path.field("relativeTimeInterval");
x.validate(&p)?;
}
if let Some(x) = &self.e_price_level {
let p = path.field("ePriceLevel");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.consumption_cost {
let p = path.field("consumptionCost");
v::items(x, Some(1), Some(3), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SampledValue {
/// Indicates the measured value.
#[serde(rename = "value")]
pub value: f64,
#[serde(rename = "measurand", default, skip_serializing_if = "Option::is_none")]
pub measurand: Option<MeasurandEnum>,
#[serde(rename = "context", default, skip_serializing_if = "Option::is_none")]
pub context: Option<ReadingContextEnum>,
#[serde(rename = "phase", default, skip_serializing_if = "Option::is_none")]
pub phase: Option<PhaseEnum>,
#[serde(rename = "location", default, skip_serializing_if = "Option::is_none")]
pub location: Option<LocationEnum>,
#[serde(
rename = "signedMeterValue",
default,
skip_serializing_if = "Option::is_none"
)]
pub signed_meter_value: Option<SignedMeterValue>,
#[serde(
rename = "unitOfMeasure",
default,
skip_serializing_if = "Option::is_none"
)]
pub unit_of_measure: Option<UnitOfMeasure>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SampledValue {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.signed_meter_value {
let p = path.field("signedMeterValue");
x.validate(&p)?;
}
if let Some(x) = &self.unit_of_measure {
let p = path.field("unitOfMeasure");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to hold parameters of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SetMonitoringData {
/// An id SHALL only be given to replace an existing monitor. The Charging Station handles the generation of id's for new monitors.
#[serde(rename = "id", default, skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(
rename = "periodicEventStream",
default,
skip_serializing_if = "Option::is_none"
)]
pub periodic_event_stream: Option<PeriodicEventStreamParams>,
/// Monitor only active when a transaction is ongoing on a component relevant to this transaction. Default = false.
#[serde(
rename = "transaction",
default,
skip_serializing_if = "Option::is_none"
)]
pub transaction: Option<bool>,
/// Value for threshold or delta monitoring.
/// For Periodic or PeriodicClockAligned this is the interval in seconds.
#[serde(rename = "value")]
pub value: f64,
#[serde(rename = "type")]
pub r#type: MonitorEnum,
/// 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.
#[serde(rename = "severity")]
pub severity: i64,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SetMonitoringData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.id {
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.periodic_event_stream {
let p = path.field("periodicEventStream");
x.validate(&p)?;
}
{
let x = &self.severity;
let p = path.field("severity");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Class to hold result of SetVariableMonitoring request.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SetMonitoringResult {
/// 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.
#[serde(rename = "id", default, skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(
rename = "statusInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub status_info: Option<StatusInfo>,
#[serde(rename = "status")]
pub status: SetMonitoringStatusEnum,
#[serde(rename = "type")]
pub r#type: MonitorEnum,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
/// 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.
#[serde(rename = "severity")]
pub severity: i64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SetMonitoringResult {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.id {
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.status_info {
let p = path.field("statusInfo");
x.validate(&p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
{
let x = &self.severity;
let p = path.field("severity");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SetVariableData {
#[serde(
rename = "attributeType",
default,
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.
#[serde(rename = "attributeValue")]
pub attribute_value: String,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SetVariableData {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.attribute_value;
let p = path.field("attributeValue");
v::max_length(x, 2500, &p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SetVariableResult {
#[serde(
rename = "attributeType",
default,
skip_serializing_if = "Option::is_none"
)]
pub attribute_type: Option<AttributeEnum>,
#[serde(rename = "attributeStatus")]
pub attribute_status: SetVariableStatusEnum,
#[serde(
rename = "attributeStatusInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub attribute_status_info: Option<StatusInfo>,
#[serde(rename = "component")]
pub component: Component,
#[serde(rename = "variable")]
pub variable: Variable,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SetVariableResult {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.attribute_status_info {
let p = path.field("attributeStatusInfo");
x.validate(&p)?;
}
{
let x = &self.component;
let p = path.field("component");
x.validate(&p)?;
}
{
let x = &self.variable;
let p = path.field("variable");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Represent a signed version of the meter value.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SignedMeterValue {
/// 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.
#[serde(rename = "signedMeterData")]
pub signed_meter_data: 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.
#[serde(
rename = "signingMethod",
default,
skip_serializing_if = "Option::is_none"
)]
pub signing_method: Option<String>,
/// Format used by the energy meter to encode the meter data. For example: OCMF or EDL.
#[serde(rename = "encodingMethod")]
pub encoding_method: String,
/// *(2.1)* Base64 encoded, sending depends on configuration variable _PublicKeyWithSignedMeterValue_.
#[serde(rename = "publicKey", default, skip_serializing_if = "Option::is_none")]
pub public_key: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for SignedMeterValue {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.signed_meter_data;
let p = path.field("signedMeterData");
v::max_length(x, 32768, &p)?;
}
if let Some(x) = &self.signing_method {
let p = path.field("signingMethod");
v::max_length(x, 50, &p)?;
}
{
let x = &self.encoding_method;
let p = path.field("encodingMethod");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.public_key {
let p = path.field("publicKey");
v::max_length(x, 2500, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Element providing more information about the status.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StatusInfo {
/// A predefined code for the reason why the status is returned in this response. The string is case-insensitive.
#[serde(rename = "reasonCode")]
pub reason_code: String,
/// Additional text to provide detailed information.
#[serde(
rename = "additionalInfo",
default,
skip_serializing_if = "Option::is_none"
)]
pub additional_info: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for StatusInfo {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.reason_code;
let p = path.field("reasonCode");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.additional_info {
let p = path.field("additionalInfo");
v::max_length(x, 1024, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StreamDataElement {
/// Offset relative to _basetime_ of this message. _basetime_ + _t_ is timestamp of recorded value.
#[serde(rename = "t")]
pub t: f64,
#[serde(rename = "v")]
pub v: String,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for StreamDataElement {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.v;
let p = path.field("v");
v::max_length(x, 2500, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// 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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Tariff {
/// Unique id of tariff
#[serde(rename = "tariffId")]
pub tariff_id: String,
#[serde(
rename = "description",
default,
skip_serializing_if = "Option::is_none"
)]
pub description: Option<Vec<MessageContent>>,
/// Currency code according to ISO 4217
#[serde(rename = "currency")]
pub currency: String,
#[serde(rename = "energy", default, skip_serializing_if = "Option::is_none")]
pub energy: Option<TariffEnergy>,
/// Time when this tariff becomes active. When absent, it is immediately active.
#[serde(rename = "validFrom", default, skip_serializing_if = "Option::is_none")]
pub valid_from: Option<DateTime>,
#[serde(
rename = "chargingTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_time: Option<TariffTime>,
#[serde(rename = "idleTime", default, skip_serializing_if = "Option::is_none")]
pub idle_time: Option<TariffTime>,
#[serde(rename = "fixedFee", default, skip_serializing_if = "Option::is_none")]
pub fixed_fee: Option<TariffFixed>,
#[serde(
rename = "reservationTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub reservation_time: Option<TariffTime>,
#[serde(
rename = "reservationFixed",
default,
skip_serializing_if = "Option::is_none"
)]
pub reservation_fixed: Option<TariffFixed>,
#[serde(rename = "minCost", default, skip_serializing_if = "Option::is_none")]
pub min_cost: Option<Price>,
#[serde(rename = "maxCost", default, skip_serializing_if = "Option::is_none")]
pub max_cost: Option<Price>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Tariff {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.tariff_id;
let p = path.field("tariffId");
v::max_length(x, 60, &p)?;
}
if let Some(x) = &self.description {
let p = path.field("description");
v::items(x, Some(1), Some(10), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
{
let x = &self.currency;
let p = path.field("currency");
v::max_length(x, 3, &p)?;
}
if let Some(x) = &self.energy {
let p = path.field("energy");
x.validate(&p)?;
}
if let Some(x) = &self.charging_time {
let p = path.field("chargingTime");
x.validate(&p)?;
}
if let Some(x) = &self.idle_time {
let p = path.field("idleTime");
x.validate(&p)?;
}
if let Some(x) = &self.fixed_fee {
let p = path.field("fixedFee");
x.validate(&p)?;
}
if let Some(x) = &self.reservation_time {
let p = path.field("reservationTime");
x.validate(&p)?;
}
if let Some(x) = &self.reservation_fixed {
let p = path.field("reservationFixed");
x.validate(&p)?;
}
if let Some(x) = &self.min_cost {
let p = path.field("minCost");
x.validate(&p)?;
}
if let Some(x) = &self.max_cost {
let p = path.field("maxCost");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Shows assignment of tariffs to EVSE or IdToken.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffAssignment {
/// Tariff id.
#[serde(rename = "tariffId")]
pub tariff_id: String,
#[serde(rename = "tariffKind")]
pub tariff_kind: TariffKindEnum,
/// Date/time when this tariff become active.
#[serde(rename = "validFrom", default, skip_serializing_if = "Option::is_none")]
pub valid_from: Option<DateTime>,
#[serde(rename = "evseIds", default, skip_serializing_if = "Option::is_none")]
pub evse_ids: Option<Vec<i64>>,
/// IdTokens related to tariff
#[serde(rename = "idTokens", default, skip_serializing_if = "Option::is_none")]
pub id_tokens: Option<Vec<String>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffAssignment {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.tariff_id;
let p = path.field("tariffId");
v::max_length(x, 60, &p)?;
}
if let Some(x) = &self.evse_ids {
let p = path.field("evseIds");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
v::minimum(*it0, 0i64, &p0)?;
}
}
if let Some(x) = &self.id_tokens {
let p = path.field("idTokens");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
v::max_length(it0, 255, &p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffConditions {
/// 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\]
#[serde(
rename = "startTimeOfDay",
default,
skip_serializing_if = "Option::is_none"
)]
pub start_time_of_day: Option<String>,
/// 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.
#[serde(
rename = "endTimeOfDay",
default,
skip_serializing_if = "Option::is_none"
)]
pub end_time_of_day: Option<String>,
/// Day(s) of the week this is tariff applies.
#[serde(rename = "dayOfWeek", default, skip_serializing_if = "Option::is_none")]
pub day_of_week: Option<Vec<DayOfWeekEnum>>,
/// 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\])
#[serde(
rename = "validFromDate",
default,
skip_serializing_if = "Option::is_none"
)]
pub valid_from_date: Option<String>,
/// End date in local time, for example: 2015-12-27.
/// Valid until this day (exclusive). Same syntax as _validFromDate_.
#[serde(
rename = "validToDate",
default,
skip_serializing_if = "Option::is_none"
)]
pub valid_to_date: Option<String>,
#[serde(rename = "evseKind", default, skip_serializing_if = "Option::is_none")]
pub evse_kind: Option<EvseKindEnum>,
/// Minimum consumed energy in Wh, for example 20000 Wh.
/// Valid from this amount of energy (inclusive) being used.
#[serde(rename = "minEnergy", default, skip_serializing_if = "Option::is_none")]
pub min_energy: Option<f64>,
/// Maximum consumed energy in Wh, for example 50000 Wh.
/// Valid until this amount of energy (exclusive) being used.
#[serde(rename = "maxEnergy", default, skip_serializing_if = "Option::is_none")]
pub max_energy: Option<f64>,
/// 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.
#[serde(
rename = "minCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_current: Option<f64>,
/// 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.
#[serde(
rename = "maxCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_current: Option<f64>,
/// 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.
#[serde(rename = "minPower", default, skip_serializing_if = "Option::is_none")]
pub min_power: Option<f64>,
/// 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.
#[serde(rename = "maxPower", default, skip_serializing_if = "Option::is_none")]
pub max_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.
#[serde(rename = "minTime", default, skip_serializing_if = "Option::is_none")]
pub min_time: Option<i64>,
/// 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.
#[serde(rename = "maxTime", default, 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.
#[serde(
rename = "minChargingTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_charging_time: Option<i64>,
/// 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.
#[serde(
rename = "maxChargingTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_charging_time: Option<i64>,
/// 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.
#[serde(
rename = "minIdleTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_idle_time: Option<i64>,
/// 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.
#[serde(
rename = "maxIdleTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_idle_time: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffConditions {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.day_of_week {
let p = path.field("dayOfWeek");
v::items(x, Some(1), Some(7), &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffConditionsFixed {
/// 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\]
#[serde(
rename = "startTimeOfDay",
default,
skip_serializing_if = "Option::is_none"
)]
pub start_time_of_day: Option<String>,
/// 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.
#[serde(
rename = "endTimeOfDay",
default,
skip_serializing_if = "Option::is_none"
)]
pub end_time_of_day: Option<String>,
/// Day(s) of the week this is tariff applies.
#[serde(rename = "dayOfWeek", default, skip_serializing_if = "Option::is_none")]
pub day_of_week: Option<Vec<DayOfWeekEnum>>,
/// 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\])
#[serde(
rename = "validFromDate",
default,
skip_serializing_if = "Option::is_none"
)]
pub valid_from_date: Option<String>,
/// End date in local time, for example: 2015-12-27.
/// Valid until this day (exclusive). Same syntax as _validFromDate_.
#[serde(
rename = "validToDate",
default,
skip_serializing_if = "Option::is_none"
)]
pub valid_to_date: Option<String>,
#[serde(rename = "evseKind", default, 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".
#[serde(
rename = "paymentBrand",
default,
skip_serializing_if = "Option::is_none"
)]
pub payment_brand: Option<String>,
/// Type of adhoc payment, e.g. CC, Debit.
/// Based on value of _additionalIdToken_ from _idToken.additionalInfo.type_ = "PaymentRecognition".
#[serde(
rename = "paymentRecognition",
default,
skip_serializing_if = "Option::is_none"
)]
pub payment_recognition: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffConditionsFixed {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.day_of_week {
let p = path.field("dayOfWeek");
v::items(x, Some(1), Some(7), &p)?;
}
if let Some(x) = &self.payment_brand {
let p = path.field("paymentBrand");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.payment_recognition {
let p = path.field("paymentRecognition");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Price elements and tax for energy
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffEnergy {
#[serde(rename = "prices")]
pub prices: Vec<TariffEnergyPrice>,
#[serde(rename = "taxRates", default, skip_serializing_if = "Option::is_none")]
pub tax_rates: Option<Vec<TaxRate>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffEnergy {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.prices;
let p = path.field("prices");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.tax_rates {
let p = path.field("taxRates");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Tariff with optional conditions for an energy price.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffEnergyPrice {
/// Price per kWh (excl. tax) for this element.
#[serde(rename = "priceKwh")]
pub price_kwh: f64,
#[serde(
rename = "conditions",
default,
skip_serializing_if = "Option::is_none"
)]
pub conditions: Option<TariffConditions>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffEnergyPrice {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.conditions {
let p = path.field("conditions");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffFixed {
#[serde(rename = "prices")]
pub prices: Vec<TariffFixedPrice>,
#[serde(rename = "taxRates", default, skip_serializing_if = "Option::is_none")]
pub tax_rates: Option<Vec<TaxRate>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffFixed {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.prices;
let p = path.field("prices");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.tax_rates {
let p = path.field("taxRates");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Tariff with optional conditions for a fixed price.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffFixedPrice {
#[serde(
rename = "conditions",
default,
skip_serializing_if = "Option::is_none"
)]
pub conditions: Option<TariffConditionsFixed>,
/// Fixed price for this element e.g. a start fee.
#[serde(rename = "priceFixed")]
pub price_fixed: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffFixedPrice {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.conditions {
let p = path.field("conditions");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Price elements and tax for time
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffTime {
#[serde(rename = "prices")]
pub prices: Vec<TariffTimePrice>,
#[serde(rename = "taxRates", default, skip_serializing_if = "Option::is_none")]
pub tax_rates: Option<Vec<TaxRate>>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffTime {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.prices;
let p = path.field("prices");
v::items(x, Some(1), None, &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.tax_rates {
let p = path.field("taxRates");
v::items(x, Some(1), Some(5), &p)?;
for (i0, it0) in x.iter().enumerate() {
let p0 = p.index(i0);
it0.validate(&p0)?;
}
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Tariff with optional conditions for a time duration price.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TariffTimePrice {
/// Price per minute (excl. tax) for this element.
#[serde(rename = "priceMinute")]
pub price_minute: f64,
#[serde(
rename = "conditions",
default,
skip_serializing_if = "Option::is_none"
)]
pub conditions: Option<TariffConditions>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TariffTimePrice {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.conditions {
let p = path.field("conditions");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Tax percentage
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TaxRate {
/// Type of this tax, e.g. "Federal ", "State", for information on receipt.
#[serde(rename = "type")]
pub r#type: String,
/// Tax percentage
#[serde(rename = "tax")]
pub tax: f64,
/// 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.
#[serde(rename = "stack", default, skip_serializing_if = "Option::is_none")]
pub stack: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TaxRate {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.r#type;
let p = path.field("type");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.stack {
let p = path.field("stack");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Part of ISO 15118-20 price schedule.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TaxRule {
/// Id for the tax rule.
#[serde(rename = "taxRuleID")]
pub tax_rule_id: i64,
/// Human readable string to identify the tax rule.
#[serde(
rename = "taxRuleName",
default,
skip_serializing_if = "Option::is_none"
)]
pub tax_rule_name: Option<String>,
/// Indicates whether the tax is included in any price or not.
#[serde(
rename = "taxIncludedInPrice",
default,
skip_serializing_if = "Option::is_none"
)]
pub tax_included_in_price: Option<bool>,
/// Indicates whether this tax applies to Energy Fees.
#[serde(rename = "appliesToEnergyFee")]
pub applies_to_energy_fee: bool,
/// Indicates whether this tax applies to Parking Fees.
#[serde(rename = "appliesToParkingFee")]
pub applies_to_parking_fee: bool,
/// Indicates whether this tax applies to Overstay Fees.
#[serde(rename = "appliesToOverstayFee")]
pub applies_to_overstay_fee: bool,
/// Indicates whether this tax applies to Minimum/Maximum Cost.
#[serde(rename = "appliesToMinimumMaximumCost")]
pub applies_to_minimum_maximum_cost: bool,
#[serde(rename = "taxRate")]
pub tax_rate: RationalNumber,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TaxRule {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.tax_rule_id;
let p = path.field("taxRuleID");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.tax_rule_name {
let p = path.field("taxRuleName");
v::max_length(x, 100, &p)?;
}
{
let x = &self.tax_rate;
let p = path.field("taxRate");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TotalCost {
/// Currency of the costs in ISO 4217 Code.
#[serde(rename = "currency")]
pub currency: String,
#[serde(rename = "typeOfCost")]
pub type_of_cost: TariffCostEnum,
#[serde(rename = "fixed", default, skip_serializing_if = "Option::is_none")]
pub fixed: Option<Price>,
#[serde(rename = "energy", default, skip_serializing_if = "Option::is_none")]
pub energy: Option<Price>,
#[serde(
rename = "chargingTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_time: Option<Price>,
#[serde(rename = "idleTime", default, skip_serializing_if = "Option::is_none")]
pub idle_time: Option<Price>,
#[serde(
rename = "reservationTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub reservation_time: Option<Price>,
#[serde(
rename = "reservationFixed",
default,
skip_serializing_if = "Option::is_none"
)]
pub reservation_fixed: Option<Price>,
#[serde(rename = "total")]
pub total: TotalPrice,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TotalCost {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.currency;
let p = path.field("currency");
v::max_length(x, 3, &p)?;
}
if let Some(x) = &self.fixed {
let p = path.field("fixed");
x.validate(&p)?;
}
if let Some(x) = &self.energy {
let p = path.field("energy");
x.validate(&p)?;
}
if let Some(x) = &self.charging_time {
let p = path.field("chargingTime");
x.validate(&p)?;
}
if let Some(x) = &self.idle_time {
let p = path.field("idleTime");
x.validate(&p)?;
}
if let Some(x) = &self.reservation_time {
let p = path.field("reservationTime");
x.validate(&p)?;
}
if let Some(x) = &self.reservation_fixed {
let p = path.field("reservationFixed");
x.validate(&p)?;
}
{
let x = &self.total;
let p = path.field("total");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TotalPrice {
/// Price/cost excluding tax. Can be absent if _inclTax_ is present.
#[serde(rename = "exclTax", default, skip_serializing_if = "Option::is_none")]
pub excl_tax: Option<f64>,
/// Price/cost including tax. Can be absent if _exclTax_ is present.
#[serde(rename = "inclTax", default, skip_serializing_if = "Option::is_none")]
pub incl_tax: Option<f64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TotalPrice {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// This contains the calculated usage of energy, charging time and idle time during a transaction.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TotalUsage {
#[serde(rename = "energy")]
pub energy: f64,
/// Total duration of the charging session (including the duration of charging and not charging), in seconds.
#[serde(rename = "chargingTime")]
pub charging_time: i64,
/// Total duration of the charging session where the EV was not charging (no energy was transferred between EVSE and EV), in seconds.
#[serde(rename = "idleTime")]
pub idle_time: i64,
/// Total time of reservation in seconds.
#[serde(
rename = "reservationTime",
default,
skip_serializing_if = "Option::is_none"
)]
pub reservation_time: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TotalUsage {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Transaction {
/// This contains the Id of the transaction.
#[serde(rename = "transactionId")]
pub transaction_id: String,
#[serde(
rename = "chargingState",
default,
skip_serializing_if = "Option::is_none"
)]
pub charging_state: Option<ChargingStateEnum>,
/// 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.
#[serde(
rename = "timeSpentCharging",
default,
skip_serializing_if = "Option::is_none"
)]
pub time_spent_charging: Option<i64>,
#[serde(
rename = "stoppedReason",
default,
skip_serializing_if = "Option::is_none"
)]
pub stopped_reason: Option<ReasonEnum>,
/// The ID given to remote start request (<<requeststarttransactionrequest, RequestStartTransactionRequest>>. This enables to CSMS to match the started transaction to the given start request.
#[serde(
rename = "remoteStartId",
default,
skip_serializing_if = "Option::is_none"
)]
pub remote_start_id: Option<i64>,
#[serde(
rename = "operationMode",
default,
skip_serializing_if = "Option::is_none"
)]
pub operation_mode: Option<OperationModeEnum>,
/// *(2.1)* Id of tariff in use for transaction
#[serde(rename = "tariffId", default, skip_serializing_if = "Option::is_none")]
pub tariff_id: Option<String>,
#[serde(
rename = "transactionLimit",
default,
skip_serializing_if = "Option::is_none"
)]
pub transaction_limit: Option<TransactionLimit>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Transaction {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.transaction_id;
let p = path.field("transactionId");
v::max_length(x, 36, &p)?;
}
if let Some(x) = &self.tariff_id {
let p = path.field("tariffId");
v::max_length(x, 60, &p)?;
}
if let Some(x) = &self.transaction_limit {
let p = path.field("transactionLimit");
x.validate(&p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Cost, energy, time or SoC limit for a transaction.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TransactionLimit {
/// Maximum allowed cost of transaction in currency of tariff.
#[serde(rename = "maxCost", default, skip_serializing_if = "Option::is_none")]
pub max_cost: Option<f64>,
/// Maximum allowed energy in Wh to charge in transaction.
#[serde(rename = "maxEnergy", default, skip_serializing_if = "Option::is_none")]
pub max_energy: Option<f64>,
/// Maximum duration of transaction in seconds from start to end.
#[serde(rename = "maxTime", default, skip_serializing_if = "Option::is_none")]
pub max_time: Option<i64>,
/// Maximum State of Charge of EV in percentage.
#[serde(rename = "maxSoC", default, skip_serializing_if = "Option::is_none")]
pub max_so_c: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for TransactionLimit {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.max_so_c {
let p = path.field("maxSoC");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Represents a UnitOfMeasure with a multiplier
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UnitOfMeasure {
/// 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.
#[serde(rename = "unit", default, skip_serializing_if = "Option::is_none")]
pub unit: Option<String>,
/// 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.
#[serde(
rename = "multiplier",
default,
skip_serializing_if = "Option::is_none"
)]
pub multiplier: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for UnitOfMeasure {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.unit {
let p = path.field("unit");
v::max_length(x, 20, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
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, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct V2XChargingParameters {
/// 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
#[serde(
rename = "minChargePower",
default,
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
#[serde(
rename = "minChargePower_L2",
default,
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
#[serde(
rename = "minChargePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_charge_power_l3: 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
#[serde(
rename = "maxChargePower",
default,
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
#[serde(
rename = "maxChargePower_L2",
default,
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
#[serde(
rename = "maxChargePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_charge_power_l3: 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
#[serde(
rename = "minDischargePower",
default,
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
#[serde(
rename = "minDischargePower_L2",
default,
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
#[serde(
rename = "minDischargePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_discharge_power_l3: 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
#[serde(
rename = "maxDischargePower",
default,
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
#[serde(
rename = "maxDischargePower_L2",
default,
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
#[serde(
rename = "maxDischargePower_L3",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_discharge_power_l3: Option<f64>,
/// Minimum charge current in A, defined by max(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumChargeCurrent
#[serde(
rename = "minChargeCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_charge_current: Option<f64>,
/// Maximum charge current in A, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumChargeCurrent
#[serde(
rename = "maxChargeCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_charge_current: Option<f64>,
/// Minimum discharge current in A, defined by max(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumDischargeCurrent
#[serde(
rename = "minDischargeCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_discharge_current: Option<f64>,
/// Maximum discharge current in A, defined by min(EV, EVSE). Value >= 0.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumDischargeCurrent
#[serde(
rename = "maxDischargeCurrent",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_discharge_current: Option<f64>,
/// Minimum voltage in V, defined by max(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMinimumVoltage
#[serde(
rename = "minVoltage",
default,
skip_serializing_if = "Option::is_none"
)]
pub min_voltage: Option<f64>,
/// Maximum voltage in V, defined by min(EV, EVSE)
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: EVMaximumVoltage
#[serde(
rename = "maxVoltage",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_voltage: Option<f64>,
/// Energy to requested state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVTargetEnergyRequest
#[serde(
rename = "evTargetEnergyRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_target_energy_request: Option<f64>,
/// Energy to minimum allowed state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVMinimumEnergyRequest
#[serde(
rename = "evMinEnergyRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_min_energy_request: Option<f64>,
/// Energy to maximum state of charge in Wh
/// Relates to:
/// *ISO 15118-20*: Dynamic/Scheduled_SEReqControlModeType: EVMaximumEnergyRequest
#[serde(
rename = "evMaxEnergyRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_max_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
#[serde(
rename = "evMinV2XEnergyRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_min_v2_x_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
#[serde(
rename = "evMaxV2XEnergyRequest",
default,
skip_serializing_if = "Option::is_none"
)]
pub ev_max_v2_x_energy_request: Option<f64>,
/// Target state of charge at departure as percentage.
/// Relates to:
/// *ISO 15118-20*: BPT_DC_CPDReqEnergyTransferModeType: TargetSOC
#[serde(rename = "targetSoC", default, skip_serializing_if = "Option::is_none")]
pub target_so_c: Option<i64>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for V2XChargingParameters {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.target_so_c {
let p = path.field("targetSoC");
v::minimum(*x, 0i64, &p)?;
v::maximum(*x, 100i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* A point of a frequency-watt curve.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct V2XFreqWattPoint {
/// Net frequency in Hz.
#[serde(rename = "frequency")]
pub frequency: f64,
/// Power in W to charge (positive) or discharge (negative) at specified frequency.
#[serde(rename = "power")]
pub power: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for V2XFreqWattPoint {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// *(2.1)* A point of a signal-watt curve.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct V2XSignalWattPoint {
/// Signal value from an AFRRSignalRequest.
#[serde(rename = "signal")]
pub signal: i64,
/// Power in W to charge (positive) or discharge (negative) at specified frequency.
#[serde(rename = "power")]
pub power: f64,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for V2XSignalWattPoint {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// VPN Configuration settings
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VPN {
/// VPN Server Address
#[serde(rename = "server")]
pub server: String,
/// VPN User
#[serde(rename = "user")]
pub user: String,
/// VPN group.
#[serde(rename = "group", default, skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
/// *(2.1)* VPN Password.
#[serde(rename = "password")]
pub password: String,
/// VPN shared secret.
#[serde(rename = "key")]
pub key: String,
#[serde(rename = "type")]
pub r#type: VPNEnum,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for VPN {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.server;
let p = path.field("server");
v::max_length(x, 2000, &p)?;
}
{
let x = &self.user;
let p = path.field("user");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.group {
let p = path.field("group");
v::max_length(x, 50, &p)?;
}
{
let x = &self.password;
let p = path.field("password");
v::max_length(x, 64, &p)?;
}
{
let x = &self.key;
let p = path.field("key");
v::max_length(x, 255, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Reference key to a component-variable.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Variable {
/// 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.
#[serde(rename = "name")]
pub name: String,
/// Name of instance in case the variable exists as multiple instances. Case Insensitive. strongly advised to use Camel Case.
#[serde(rename = "instance", default, skip_serializing_if = "Option::is_none")]
pub instance: Option<String>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for Variable {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.name;
let p = path.field("name");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.instance {
let p = path.field("instance");
v::max_length(x, 50, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Attribute data of a variable.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VariableAttribute {
#[serde(rename = "type", default, 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.
#[serde(rename = "value", default, skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(
rename = "mutability",
default,
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.
#[serde(
rename = "persistent",
default,
skip_serializing_if = "Option::is_none"
)]
pub persistent: Option<bool>,
/// If true, value that will never be changed by the Charging Station at runtime. Default when omitted is false.
#[serde(rename = "constant", default, skip_serializing_if = "Option::is_none")]
pub constant: Option<bool>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for VariableAttribute {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.value {
let p = path.field("value");
v::max_length(x, 2500, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// Fixed read-only parameters of a variable.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VariableCharacteristics {
/// Unit of the variable. When the transmitted value has a unit, this field SHALL be included.
#[serde(rename = "unit", default, skip_serializing_if = "Option::is_none")]
pub unit: Option<String>,
#[serde(rename = "dataType")]
pub data_type: DataEnum,
/// Minimum possible value of this variable.
#[serde(rename = "minLimit", default, skip_serializing_if = "Option::is_none")]
pub min_limit: Option<f64>,
/// 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.
#[serde(rename = "maxLimit", default, skip_serializing_if = "Option::is_none")]
pub max_limit: Option<f64>,
/// *(2.1)* Maximum number of elements from _valuesList_ that are supported as _attributeValue_.
#[serde(
rename = "maxElements",
default,
skip_serializing_if = "Option::is_none"
)]
pub max_elements: Option<i64>,
/// 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.
#[serde(
rename = "valuesList",
default,
skip_serializing_if = "Option::is_none"
)]
pub values_list: Option<String>,
/// Flag indicating if this variable supports monitoring.
#[serde(rename = "supportsMonitoring")]
pub supports_monitoring: bool,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for VariableCharacteristics {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.unit {
let p = path.field("unit");
v::max_length(x, 16, &p)?;
}
if let Some(x) = &self.max_elements {
let p = path.field("maxElements");
v::minimum(*x, 1i64, &p)?;
}
if let Some(x) = &self.values_list {
let p = path.field("valuesList");
v::max_length(x, 1000, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
/// A monitoring setting for a variable.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VariableMonitoring {
/// Identifies the monitor.
#[serde(rename = "id")]
pub id: i64,
/// Monitor only active when a transaction is ongoing on a component relevant to this transaction.
#[serde(rename = "transaction")]
pub transaction: bool,
/// Value for threshold or delta monitoring.
/// For Periodic or PeriodicClockAligned this is the interval in seconds.
#[serde(rename = "value")]
pub value: f64,
#[serde(rename = "type")]
pub r#type: MonitorEnum,
/// 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.
#[serde(rename = "severity")]
pub severity: i64,
#[serde(rename = "eventNotificationType")]
pub event_notification_type: EventNotificationEnum,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for VariableMonitoring {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
{
let x = &self.id;
let p = path.field("id");
v::minimum(*x, 0i64, &p)?;
}
{
let x = &self.severity;
let p = path.field("severity");
v::minimum(*x, 0i64, &p)?;
}
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VoltageParams {
/// 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.
#[serde(
rename = "hv10MinMeanValue",
default,
skip_serializing_if = "Option::is_none"
)]
pub hv10_min_mean_value: Option<f64>,
/// 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.
#[serde(
rename = "hv10MinMeanTripDelay",
default,
skip_serializing_if = "Option::is_none"
)]
pub hv10_min_mean_trip_delay: Option<f64>,
#[serde(
rename = "powerDuringCessation",
default,
skip_serializing_if = "Option::is_none"
)]
pub power_during_cessation: Option<PowerDuringCessationEnum>,
#[serde(
rename = "customData",
default,
skip_serializing_if = "Option::is_none"
)]
pub custom_data: Option<CustomData>,
}
impl Validate for VoltageParams {
fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
if let Some(x) = &self.custom_data {
let p = path.field("customData");
x.validate(&p)?;
}
Ok(())
}
}