grid_tariffs/
power_tariffs.rs

1use chrono::DateTime;
2use serde::Serialize;
3
4use crate::{
5    Actual, Language, PartialPowerAverage, PowerAverage, PowerTariffMatches,
6    costs::{CostPeriods, CostPeriodsSimple},
7    hours::Hours,
8};
9
10#[derive(Debug, Clone, Copy, Serialize)]
11#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
12pub struct PowerDivide {
13    pub(crate) hours: Option<Hours>,
14    divider: u8,
15}
16
17impl PowerDivide {
18    pub const fn new(hours: Option<Hours>, divider: u8) -> Self {
19        Self { hours, divider }
20    }
21
22    pub fn hours(&self) -> Option<Hours> {
23        self.hours
24    }
25
26    pub fn divider<Tz: chrono::TimeZone>(&self, timestamp: DateTime<Tz>) -> u8 {
27        if let Some(hours) = self.hours()
28            && hours.matches(timestamp)
29        {
30            self.divider
31        } else {
32            1
33        }
34    }
35
36    pub fn multiplier<Tz: chrono::TimeZone>(&self, timestamp: DateTime<Tz>) -> f64 {
37        1. / self.divider(timestamp) as f64
38    }
39}
40
41#[derive(Debug, Clone, Serialize)]
42#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
43pub enum PowerTariff {
44    Unverified,
45    NotImplemented,
46    Periods {
47        method: TariffCalculationMethod,
48        /// Divide kw by this amount during these hours
49        power_divide: Option<PowerDivide>,
50        periods: CostPeriods,
51    },
52}
53
54impl PowerTariff {
55    pub const fn new(method: TariffCalculationMethod, periods: CostPeriods) -> Self {
56        Self::Periods {
57            method,
58            periods,
59            power_divide: None,
60        }
61    }
62
63    pub const fn add_power_divide(self, power_divide: PowerDivide) -> Self {
64        match self {
65            Self::Unverified => unimplemented!(),
66            Self::NotImplemented => unimplemented!(),
67            Self::Periods {
68                method,
69                power_divide: _,
70                periods,
71            } => Self::Periods {
72                method,
73                power_divide: Some(power_divide),
74                periods,
75            },
76        }
77    }
78
79    pub const fn is_unverified(&self) -> bool {
80        matches!(self, Self::Unverified)
81    }
82
83    pub fn simplified(
84        &self,
85        fuse_size: u16,
86        yearly_consumption: u32,
87        language: Language,
88    ) -> PowerTariffSimplified {
89        PowerTariffSimplified::new(self, fuse_size, yearly_consumption, language)
90    }
91
92    pub fn periods(
93        &self,
94        averages: Vec<PowerAverage<Actual>>,
95        current_power_average: Option<PartialPowerAverage>,
96    ) -> PowerTariffMatches {
97        match self {
98            PowerTariff::Unverified => PowerTariffMatches::new_dummy(),
99            PowerTariff::NotImplemented => PowerTariffMatches::new_dummy(),
100            PowerTariff::Periods {
101                method,
102                periods,
103                power_divide,
104            } => PowerTariffMatches::new(
105                *method,
106                *power_divide,
107                *periods,
108                &averages
109                    .iter()
110                    .map(|a| a.into_virtual(*power_divide))
111                    .collect::<Vec<_>>(),
112                current_power_average,
113            ),
114        }
115    }
116}
117
118/// The method used to calculate power tariffs
119#[derive(Debug, Clone, Copy, Serialize)]
120#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
121pub enum TariffCalculationMethod {
122    /// Power peak for top hour of the top x days of the month
123    AverageDays(u8),
124    /// Average of top x hours of the month
125    AverageHours(u8),
126}
127
128/// Like PowerTariff, but with costs being simple Money objects
129#[derive(Debug, Clone, Serialize)]
130#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
131pub enum PowerTariffSimplified {
132    Unverified,
133    NotImplemented,
134    Periods {
135        method: TariffCalculationMethod,
136        /// Divide kw by this amount during these hours
137        power_divide: Option<PowerDivide>,
138        periods: CostPeriodsSimple,
139    },
140}
141
142impl PowerTariffSimplified {
143    fn new(fee: &PowerTariff, fuse_size: u16, yearly_consumption: u32, language: Language) -> Self {
144        match *fee {
145            PowerTariff::Unverified => PowerTariffSimplified::Unverified,
146            PowerTariff::NotImplemented => PowerTariffSimplified::NotImplemented,
147            PowerTariff::Periods {
148                method,
149                periods,
150                power_divide,
151            } => PowerTariffSimplified::Periods {
152                method,
153                power_divide,
154                periods: CostPeriodsSimple::new(periods, fuse_size, yearly_consumption, language),
155            },
156        }
157    }
158}