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 x days of the month
63    AverageDays(u8),
64    /// Average of top x 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    // Count one peak hour per mont0h, per specified load type
72    PeakHours(&'static [LoadType]),
73    /// Daytime and nighttime are calculated with different values
74    // TODO: How can this be extracted from CostPeriods...?!
75    AverageDayNightDifferentiated {
76        day: i32,
77        night: i32,
78    },
79}
80
81impl TariffCalculationMethod {
82    pub(super) fn relevant_samples(
83        &self,
84        grid_consumption: Vec<GridConsumption>,
85    ) -> Vec<GridConsumption> {
86        //     match self {
87        //         TariffCalculationMethod::Unimplemented => vec![],
88        //         TariffCalculationMethod::AverageDays(n) => grid_consumption
89        //             .iter()
90        //             .into_group_map_by(|pm| {
91        //                 pm.timestamp()
92        //                     .with_minute(0)
93        //                     .with_second(0)
94        //                     .with_nanosecond(0)
95        //             })
96        //             .into_iter()
97        //             .map(|(_day_hour, pm)| pm.into_iter().max_by_key(|pm| pm.value()).unwrap())
98        //             .copied()
99        //             .take((*n).into())
100        //             .collect_vec(),
101        //         TariffCalculationMethod::AverageHours(n) => {
102        //             grid_consumption.sort_by_key(|hp| hp.value());
103        //             grid_consumption.into_iter().take((*n).into()).collect()
104        //         }
105        //         TariffCalculationMethod::AverageDaysDifferentiated { .. } => todo!(),
106        //         TariffCalculationMethod::AverageDayNightDifferentiated { .. } => todo!(),
107        //         TariffCalculationMethod::PeakHour => grid_consumption
108        //             .iter()
109        //             .max_by_key(|dw| dw.value())
110        //             .map(|dw| vec![*dw])
111        //             .unwrap_or_default(),
112        //     }
113        todo!()
114    }
115}
116
117#[derive(Clone, Copy)]
118pub(super) struct HourPower(DateTime<Tz>, u32);
119
120impl HourPower {
121    fn timestamp(&self) -> DateTime<Tz> {
122        self.0
123    }
124
125    fn watts(&self) -> u32 {
126        self.1
127    }
128}
129
130// // Tekniska Verken Linköping, prislista alternativ
131// // Skulle ge:
132pub struct Peak {
133    /// Non-inclusive time period
134    time_period: (DateTime<Tz>, DateTime<Tz>),
135    current_max_w: u32,
136    cost_per_kw: Money,
137    kw_divider: u8,
138}
139
140impl Peak {
141    // pub fn kwh_cost(&self, _resolution: Resolution) -> Money {
142    //     self.cost_per_kw
143    // }
144
145    pub fn contains(&self, timestamp: DateTime<Tz>) -> bool {
146        timestamp >= self.time_period.0 && timestamp < self.time_period.1
147    }
148}
149
150impl PowerTariff {
151    pub fn get_peaks(
152        &self,
153        time_period: (DateTime<Tz>, DateTime<Tz>),
154        grid_consumption: Vec<GridConsumption>,
155    ) -> Option<Vec<Peak>> {
156        let Self::Periods { method, periods } = self else {
157            return None;
158        };
159        let _samples = method.relevant_samples(grid_consumption);
160        todo!()
161    }
162}
163
164#[derive(Debug, Clone, Copy)]
165pub struct GridConsumption {
166    timestamp: DateTime<Tz>,
167    wh: u32,
168}
169
170/// Like PowerTariff, but with costs being simple Money objects
171#[derive(Debug, Clone, Serialize)]
172#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
173pub enum PowerTariffSimplified {
174    Unverified,
175    NotImplemented,
176    Periods {
177        method: TariffCalculationMethod,
178        periods: CostPeriodsSimple,
179    },
180}
181
182impl PowerTariffSimplified {
183    fn new(fee: &PowerTariff, fuse_size: u16, yearly_consumption: u32, language: Language) -> Self {
184        match *fee {
185            PowerTariff::Unverified => PowerTariffSimplified::Unverified,
186            PowerTariff::NotImplemented => PowerTariffSimplified::NotImplemented,
187            PowerTariff::Periods { method, periods } => PowerTariffSimplified::Periods {
188                method,
189                periods: CostPeriodsSimple::new(periods, fuse_size, yearly_consumption, language),
190            },
191        }
192    }
193}