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.iter().map(|a| a.into_virtual(*power_divide)).collect::<Vec<_>>(),
109                current_power_average,
110            ),
111        }
112    }
113}
114
115/// The method used to calculate power tariffs
116#[derive(Debug, Clone, Copy, Serialize)]
117#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
118pub enum TariffCalculationMethod {
119    /// Power peak for top hour of the top x days of the month
120    AverageDays(u8),
121    /// Average of top x hours of the month
122    AverageHours(u8),
123}
124
125/// Like PowerTariff, but with costs being simple Money objects
126#[derive(Debug, Clone, Serialize)]
127#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
128pub enum PowerTariffSimplified {
129    Unverified,
130    NotImplemented,
131    Periods {
132        method: TariffCalculationMethod,
133        /// Divide kw by this amount during these hours
134        power_divide: Option<PowerDivide>,
135        periods: CostPeriodsSimple,
136    },
137}
138
139impl PowerTariffSimplified {
140    fn new(fee: &PowerTariff, fuse_size: u16, yearly_consumption: u32, language: Language) -> Self {
141        match *fee {
142            PowerTariff::Unverified => PowerTariffSimplified::Unverified,
143            PowerTariff::NotImplemented => PowerTariffSimplified::NotImplemented,
144            PowerTariff::Periods {
145                method,
146                periods,
147                power_divide,
148            } => PowerTariffSimplified::Periods {
149                method,
150                power_divide,
151                periods: CostPeriodsSimple::new(periods, fuse_size, yearly_consumption, language),
152            },
153        }
154    }
155}