grid_tariffs/
power_tariffs.rs

1use chrono::DateTime;
2use chrono_tz::Tz;
3use serde::Serialize;
4
5use crate::{
6    Language, Money,
7    costs::{CostPeriods, CostPeriodsSimple, LoadType},
8};
9
10#[derive(Debug, Clone, Serialize)]
11#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
12pub enum PowerTariff {
13    Unverified,
14    NotImplemented,
15    Periods {
16        method: TariffCalculationMethod,
17        periods: CostPeriods,
18    },
19}
20
21impl PowerTariff {
22    pub const fn is_unverified(&self) -> bool {
23        matches!(self, Self::Unverified)
24    }
25
26    pub(super) const fn new(method: TariffCalculationMethod, periods: CostPeriods) -> Self {
27        Self::Periods { method, periods }
28    }
29
30    pub(super) fn kw_cost(
31        &self,
32        timestamp: DateTime<Tz>,
33        fuse_size: u16,
34        yearly_consumption: u32,
35    ) -> Money {
36        let cost = Money::ZERO;
37        match self {
38            PowerTariff::Unverified | PowerTariff::NotImplemented => cost,
39            PowerTariff::Periods { method, periods } => {
40                for period in periods.iter() {
41                    let money = period.cost().cost_for(fuse_size, yearly_consumption);
42                }
43                cost
44            }
45        }
46    }
47
48    pub fn simplified(
49        &self,
50        fuse_size: u16,
51        yearly_consumption: u32,
52        language: Language,
53    ) -> PowerTariffSimplified {
54        PowerTariffSimplified::new(self, fuse_size, yearly_consumption, language)
55    }
56}
57
58/// The method used to calculate power tariffs
59#[derive(Debug, Clone, Copy, Serialize)]
60#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
61pub enum TariffCalculationMethod {
62    /// Power peak for top hour of the top three days of the month
63    AverageDays(u8),
64    /// Average of top three hours of the month
65    AverageHours(u8),
66    /// Like AverageDays, but one for base load time and one for peak load time
67    AverageDaysDifferentiated {
68        peak: u8,
69        base: u8,
70    },
71    /// Only count the max peak hour of the month
72    PeakHour,
73    // Count one peak hour per month, per specified load type
74    PeakHours(&'static [LoadType]),
75    /// Daytime and nighttime are calculated with different values
76    // TODO: How can this be extracted from CostPeriods...?!
77    AverageDayNightDifferentiated {
78        day: i32,
79        night: i32,
80    },
81}
82
83impl TariffCalculationMethod {
84    pub(super) fn relevant_samples(
85        &self,
86        grid_consumption: Vec<GridConsumption>,
87    ) -> Vec<GridConsumption> {
88        //     match self {
89        //         TariffCalculationMethod::Unimplemented => vec![],
90        //         TariffCalculationMethod::AverageDays(n) => grid_consumption
91        //             .iter()
92        //             .into_group_map_by(|pm| {
93        //                 pm.timestamp()
94        //                     .with_minute(0)
95        //                     .with_second(0)
96        //                     .with_nanosecond(0)
97        //             })
98        //             .into_iter()
99        //             .map(|(_day_hour, pm)| pm.into_iter().max_by_key(|pm| pm.value()).unwrap())
100        //             .copied()
101        //             .take((*n).into())
102        //             .collect_vec(),
103        //         TariffCalculationMethod::AverageHours(n) => {
104        //             grid_consumption.sort_by_key(|hp| hp.value());
105        //             grid_consumption.into_iter().take((*n).into()).collect()
106        //         }
107        //         TariffCalculationMethod::AverageDaysDifferentiated { .. } => todo!(),
108        //         TariffCalculationMethod::AverageDayNightDifferentiated { .. } => todo!(),
109        //         TariffCalculationMethod::PeakHour => grid_consumption
110        //             .iter()
111        //             .max_by_key(|dw| dw.value())
112        //             .map(|dw| vec![*dw])
113        //             .unwrap_or_default(),
114        //     }
115        todo!()
116    }
117}
118
119#[derive(Clone, Copy)]
120pub(super) struct HourPower(DateTime<Tz>, u32);
121
122impl HourPower {
123    fn timestamp(&self) -> DateTime<Tz> {
124        self.0
125    }
126
127    fn watts(&self) -> u32 {
128        self.1
129    }
130}
131
132// // Tekniska Verken Linköping, prislista alternativ
133// // Skulle ge:
134pub struct Peak {
135    /// Non-inclusive time period
136    time_period: (DateTime<Tz>, DateTime<Tz>),
137    current_max_w: u32,
138    cost_per_kw: Money,
139    kw_divider: u8,
140}
141
142impl Peak {
143    // pub fn kwh_cost(&self, _resolution: Resolution) -> Money {
144    //     self.cost_per_kw
145    // }
146
147    pub fn contains(&self, timestamp: DateTime<Tz>) -> bool {
148        timestamp >= self.time_period.0 && timestamp < self.time_period.1
149    }
150}
151
152impl PowerTariff {
153    pub fn get_peaks(
154        &self,
155        time_period: (DateTime<Tz>, DateTime<Tz>),
156        grid_consumption: Vec<GridConsumption>,
157    ) -> Option<Vec<Peak>> {
158        let Self::Periods { method, periods } = self else {
159            return None;
160        };
161        let _samples = method.relevant_samples(grid_consumption);
162        todo!()
163    }
164}
165
166#[derive(Debug, Clone, Copy)]
167pub struct GridConsumption {
168    timestamp: DateTime<Tz>,
169    wh: u32,
170}
171
172/// Like PowerTariff, but with costs being simple Money objects
173#[derive(Debug, Clone, Serialize)]
174#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
175pub enum PowerTariffSimplified {
176    Unverified,
177    NotImplemented,
178    Periods {
179        method: TariffCalculationMethod,
180        periods: CostPeriodsSimple,
181    },
182}
183
184impl PowerTariffSimplified {
185    fn new(fee: &PowerTariff, fuse_size: u16, yearly_consumption: u32, language: Language) -> Self {
186        match *fee {
187            PowerTariff::Unverified => PowerTariffSimplified::Unverified,
188            PowerTariff::NotImplemented => PowerTariffSimplified::NotImplemented,
189            PowerTariff::Periods { method, periods } => PowerTariffSimplified::Periods {
190                method,
191                periods: CostPeriodsSimple::new(periods, fuse_size, yearly_consumption, language),
192            },
193        }
194    }
195}