grid_tariffs/
power_tariffs.rs

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