teleinfo_parser/
base.rs

1/*
2 * teleinfo-parser
3 * Copyright (c) 2018, 2021 Nicolas PENINGUY.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use chrono::*;
20use frame::*;
21use std::io;
22
23/// All the usefull informations that can be extracted when in the Base tariff option.
24#[derive(Debug)]
25pub struct BaseInfos {
26
27    /// The ID of the counter (ADCO)
28    pub meter_id: String,
29    /// The date and time at which the frame was received.
30    pub date: DateTime<Local>,
31    /// The current tariff period, TH
32    pub periode: String,
33    /// The value of the Base meter, in Wh.
34    pub base: i32,
35    /// The current intensity in A (informative).
36    pub iinst: i32,
37    /// Apparent power, in W (informative).
38    pub papp: i32,
39    /// True if maximum subscribed intensity is exceeded.
40    pub alerte: bool
41}
42
43struct BaseInfosBuilder {
44
45    meter_id: Option<String>,
46    date: Option<DateTime<Local>>,
47    periode: Option<String>,
48    base: Option<i32>,
49    iinst: Option<i32>,
50    papp: Option<i32>,
51    alerte: bool
52}
53
54macro_rules! get {
55    ($e:expr, $msg:expr) => (match $e { Some(e) => e, None => return Err(TeleinfoError::FrameError($msg.to_string())) })
56}
57
58impl BaseInfos {
59
60    /// Try to read informations from the next frame. Any lowlevel error in the frame
61    /// (e.g. wrong checksum) will be returned as is. Additionnaly, the function will
62    /// ensure that all the expected fields are indeed present. If not, a FrameError will be
63    /// returned.
64    pub fn read<T: io::Read>(mut input: &mut T) -> Result<BaseInfos, TeleinfoError> {
65
66        let frame = Frame::next_frame(&mut input)?;
67
68        BaseInfos::from(frame)
69    }
70
71    fn from(frame: Frame) -> Result<BaseInfos, TeleinfoError> {
72
73        let mut builder = BaseInfosBuilder::new();
74        let now: DateTime<Local> = Local::now();
75
76        builder.date(now);
77
78        for tag in frame.tags {
79            match tag {
80                Tag::ADCO(v) => {
81                    builder.meter_id(&v);
82                },
83                Tag::PTEC(p) => {
84                    builder.periode(match p {
85                        PeriodeTarifaire::TH => "TH",
86                        _ => panic!("PeriodeTarifaire does not match BASE")
87                    });
88                },
89                Tag::BASE(v) => {
90                    builder.base(v);
91                },
92                Tag::IINST(v) => {
93                    builder.iinst(v);
94                },
95                Tag::PAPP(v) => {
96                    builder.papp(v);
97                },
98                Tag::ADPS(_) => {
99                    builder.alerte(true);
100                },
101                _ => ()
102            };
103        }
104
105        builder.build()
106    }
107}
108
109impl BaseInfosBuilder {
110
111    fn new() -> BaseInfosBuilder {
112        BaseInfosBuilder {
113            meter_id: None,
114            date: None,
115            periode: None,
116            base: None,
117            iinst: None,
118            papp: None,
119            alerte: false
120        }
121    }
122
123    fn date(&mut self, date: DateTime<Local>) -> &mut BaseInfosBuilder {
124        self.date = Some(date);
125        self
126    }
127
128    fn meter_id(&mut self, meter_id: &str) -> &mut BaseInfosBuilder {
129        self.meter_id = Some(meter_id.to_string());
130        self
131    }
132
133    fn periode(&mut self, periode: &str) -> &mut BaseInfosBuilder {
134        self.periode = Some(periode.to_string());
135        self
136    }
137
138    fn base(&mut self, base: i32) -> &mut BaseInfosBuilder {
139        self.base = Some(base);
140        self
141    }
142
143    fn iinst(&mut self, iinst: i32) -> &mut BaseInfosBuilder {
144        self.iinst = Some(iinst);
145        self
146    }
147
148    fn papp(&mut self, papp: i32) -> &mut BaseInfosBuilder {
149        self.papp = Some(papp);
150        self
151    }
152
153    fn alerte(&mut self, alerte: bool) -> &mut BaseInfosBuilder {
154        self.alerte = alerte;
155        self
156    }
157
158    fn build(self) -> Result<BaseInfos, TeleinfoError> {
159        let infos = BaseInfos {
160            meter_id: get!(self.meter_id, "Missing meter_id"),
161            date: get!(self.date, "Missing date"),
162            periode: get!(self.periode, "Missing periode"),
163            base: get!(self.base, "Missing base"),
164            iinst: get!(self.iinst, "Missing iinst"),
165            papp: get!(self.papp, "Missing papp"),
166            alerte: self.alerte
167        };
168
169        Ok(infos)
170    }
171}