Skip to main content

codetics_ocpp16/
datatypes.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Kevin Vavelin, Codetics (https://codetics.fr)
3
4//! OCPP 1.6 composite datatypes.
5
6use ocpp_core::DateTime;
7use ocpp_core::validate::{self as v, Path, Validate, Violation};
8use serde::{Deserialize, Serialize};
9
10use crate::enums::*;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13#[serde(deny_unknown_fields)]
14pub struct AuthorizationData {
15    #[serde(rename = "idTag")]
16    pub id_tag: String,
17    #[serde(rename = "idTagInfo", default, skip_serializing_if = "Option::is_none")]
18    pub id_tag_info: Option<IdTagInfo>,
19}
20
21impl Validate for AuthorizationData {
22    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
23        {
24            let x = &self.id_tag;
25            let p = path.field("idTag");
26            v::max_length(x, 20, &p)?;
27        }
28        if let Some(x) = &self.id_tag_info {
29            let p = path.field("idTagInfo");
30            x.validate(&p)?;
31        }
32        Ok(())
33    }
34}
35
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37#[serde(deny_unknown_fields)]
38pub struct ChargingProfile {
39    #[serde(rename = "chargingProfileId")]
40    pub charging_profile_id: i64,
41    #[serde(
42        rename = "transactionId",
43        default,
44        skip_serializing_if = "Option::is_none"
45    )]
46    pub transaction_id: Option<i64>,
47    #[serde(rename = "stackLevel")]
48    pub stack_level: i64,
49    #[serde(rename = "chargingProfilePurpose")]
50    pub charging_profile_purpose: ChargingProfilePurposeType,
51    #[serde(rename = "chargingProfileKind")]
52    pub charging_profile_kind: ChargingProfileKindType,
53    #[serde(
54        rename = "recurrencyKind",
55        default,
56        skip_serializing_if = "Option::is_none"
57    )]
58    pub recurrency_kind: Option<RecurrencyKindType>,
59    #[serde(rename = "validFrom", default, skip_serializing_if = "Option::is_none")]
60    pub valid_from: Option<DateTime>,
61    #[serde(rename = "validTo", default, skip_serializing_if = "Option::is_none")]
62    pub valid_to: Option<DateTime>,
63    #[serde(rename = "chargingSchedule")]
64    pub charging_schedule: ChargingSchedule,
65}
66
67impl Validate for ChargingProfile {
68    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
69        {
70            let x = &self.charging_schedule;
71            let p = path.field("chargingSchedule");
72            x.validate(&p)?;
73        }
74        Ok(())
75    }
76}
77
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79#[serde(deny_unknown_fields)]
80pub struct ChargingSchedule {
81    #[serde(rename = "duration", default, skip_serializing_if = "Option::is_none")]
82    pub duration: Option<i64>,
83    #[serde(
84        rename = "startSchedule",
85        default,
86        skip_serializing_if = "Option::is_none"
87    )]
88    pub start_schedule: Option<DateTime>,
89    #[serde(rename = "chargingRateUnit")]
90    pub charging_rate_unit: ChargingRateUnitType,
91    #[serde(rename = "chargingSchedulePeriod")]
92    pub charging_schedule_period: Vec<ChargingSchedulePeriod>,
93    #[serde(
94        rename = "minChargingRate",
95        default,
96        skip_serializing_if = "Option::is_none"
97    )]
98    pub min_charging_rate: Option<f64>,
99}
100
101impl Validate for ChargingSchedule {
102    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
103        {
104            let x = &self.charging_schedule_period;
105            let p = path.field("chargingSchedulePeriod");
106            for (i0, it0) in x.iter().enumerate() {
107                let p0 = p.index(i0);
108                it0.validate(&p0)?;
109            }
110        }
111        if let Some(x) = &self.min_charging_rate {
112            let p = path.field("minChargingRate");
113            v::multiple_of(*x, 0.1, &p)?;
114        }
115        Ok(())
116    }
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
120#[serde(deny_unknown_fields)]
121pub struct ChargingSchedulePeriod {
122    #[serde(rename = "startPeriod")]
123    pub start_period: i64,
124    #[serde(rename = "limit")]
125    pub limit: f64,
126    #[serde(
127        rename = "numberPhases",
128        default,
129        skip_serializing_if = "Option::is_none"
130    )]
131    pub number_phases: Option<i64>,
132}
133
134impl Validate for ChargingSchedulePeriod {
135    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
136        {
137            let x = &self.limit;
138            let p = path.field("limit");
139            v::multiple_of(*x, 0.1, &p)?;
140        }
141        Ok(())
142    }
143}
144
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146#[serde(deny_unknown_fields)]
147pub struct IdTagInfo {
148    #[serde(
149        rename = "expiryDate",
150        default,
151        skip_serializing_if = "Option::is_none"
152    )]
153    pub expiry_date: Option<DateTime>,
154    #[serde(
155        rename = "parentIdTag",
156        default,
157        skip_serializing_if = "Option::is_none"
158    )]
159    pub parent_id_tag: Option<String>,
160    #[serde(rename = "status")]
161    pub status: AuthorizationStatus,
162}
163
164impl Validate for IdTagInfo {
165    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
166        if let Some(x) = &self.parent_id_tag {
167            let p = path.field("parentIdTag");
168            v::max_length(x, 20, &p)?;
169        }
170        Ok(())
171    }
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
175#[serde(deny_unknown_fields)]
176pub struct KeyValue {
177    #[serde(rename = "key")]
178    pub key: String,
179    #[serde(rename = "readonly")]
180    pub readonly: bool,
181    #[serde(rename = "value", default, skip_serializing_if = "Option::is_none")]
182    pub value: Option<String>,
183}
184
185impl Validate for KeyValue {
186    fn validate(&self, path: &Path<'_>) -> Result<(), Violation> {
187        {
188            let x = &self.key;
189            let p = path.field("key");
190            v::max_length(x, 50, &p)?;
191        }
192        if let Some(x) = &self.value {
193            let p = path.field("value");
194            v::max_length(x, 500, &p)?;
195        }
196        Ok(())
197    }
198}
199
200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201#[serde(deny_unknown_fields)]
202pub struct MeterValue {
203    #[serde(rename = "timestamp")]
204    pub timestamp: DateTime,
205    #[serde(rename = "sampledValue")]
206    pub sampled_value: Vec<SampledValue>,
207}
208
209impl Validate for MeterValue {
210    fn validate(&self, _path: &Path<'_>) -> Result<(), Violation> {
211        Ok(())
212    }
213}
214
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
216#[serde(deny_unknown_fields)]
217pub struct SampledValue {
218    #[serde(rename = "value")]
219    pub value: String,
220    #[serde(rename = "context", default, skip_serializing_if = "Option::is_none")]
221    pub context: Option<ReadingContext>,
222    #[serde(rename = "format", default, skip_serializing_if = "Option::is_none")]
223    pub format: Option<ValueFormat>,
224    #[serde(rename = "measurand", default, skip_serializing_if = "Option::is_none")]
225    pub measurand: Option<Measurand>,
226    #[serde(rename = "phase", default, skip_serializing_if = "Option::is_none")]
227    pub phase: Option<Phase>,
228    #[serde(rename = "location", default, skip_serializing_if = "Option::is_none")]
229    pub location: Option<Location>,
230    #[serde(rename = "unit", default, skip_serializing_if = "Option::is_none")]
231    pub unit: Option<UnitOfMeasure>,
232}
233
234impl Validate for SampledValue {
235    fn validate(&self, _path: &Path<'_>) -> Result<(), Violation> {
236        Ok(())
237    }
238}