1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
use crate::{client::AuthenticatedClient, errors::Result};

use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt};

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HomesData {
    pub body: Body,
    pub status: String,
    pub time_exec: f64,
    pub time_server: i64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Body {
    pub homes: Vec<Home>,
    pub user: User,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Home {
    pub id: String,
    pub name: String,
    pub timezone: String,
    pub rooms: Vec<Room>,
    pub modules: Vec<Module>,
    pub therm_schedules: Vec<ThermSchedule>,
    pub therm_setpoint_default_duration: i64,
    pub therm_mode: String,
    pub schedules: Vec<Schedule>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Room {
    pub id: String,
    pub name: String,
    #[serde(rename = "type")]
    pub type_field: String,
    pub module_ids: Vec<String>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Module {
    pub id: String,
    #[serde(rename = "type")]
    pub type_field: String,
    pub name: String,
    pub setup_date: i64,
    pub modules_bridged: Option<Vec<String>>,
    pub room_id: Option<String>,
    pub bridge: Option<String>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ThermSchedule {
    pub timetable: Vec<Timetable>,
    pub zones: Vec<Zone>,
    pub name: String,
    pub default: bool,
    pub away_temp: i64,
    pub hg_temp: i64,
    pub id: String,
    pub selected: bool,
    #[serde(rename = "type")]
    pub type_field: String,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Timetable {
    pub zone_id: i64,
    pub m_offset: i64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Zone {
    pub name: String,
    pub id: i64,
    #[serde(rename = "type")]
    pub type_field: i64,
    pub rooms_temp: Vec<RoomsTemp>,
    pub rooms: Option<Vec<RoomTemp>>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RoomsTemp {
    pub room_id: String,
    pub temp: f64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Schedule {
    pub timetable: Vec<Timetable>,
    pub zones: Vec<Zone>,
    pub name: String,
    pub default: bool,
    pub away_temp: i64,
    pub hg_temp: i64,
    pub id: String,
    pub selected: bool,
    #[serde(rename = "type")]
    pub type_field: String,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RoomTemp {
    pub id: String,
    pub therm_setpoint_temperature: f64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct User {
    pub email: String,
    pub language: String,
    pub locale: String,
    pub feel_like_algorithm: i64,
    pub unit_pressure: i64,
    pub unit_system: i64,
    pub unit_wind: i64,
    pub id: String,
}

#[derive(Default)]
pub struct Parameters<'a> {
    home_id: Option<&'a str>,
    gateway_types: Option<&'a [GatewayType]>,
}

impl<'a> Parameters<'a> {
    pub fn new() -> Self {
        Parameters::default()
    }

    pub fn home_id(self, home_id: &'a str) -> Self {
        Parameters {
            home_id: Some(home_id),
            ..self
        }
    }

    pub fn gateway_types(self, gateway_types: &'a [GatewayType]) -> Self {
        Parameters {
            gateway_types: Some(gateway_types),
            ..self
        }
    }
}

pub enum GatewayType {
    ThermostatValve,
    Welcome,
    Presence,
}

impl fmt::Display for GatewayType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            GatewayType::ThermostatValve => "NAPLUG",
            GatewayType::Welcome => "Humidity",
            GatewayType::Presence => "NOC",
        };
        write!(f, "{}", s)
    }
}

#[allow(clippy::implicit_hasher)]
impl<'a> From<&'a Parameters<'a>> for HashMap<&str, String> {
    fn from(p: &'a Parameters) -> HashMap<&'static str, String> {
        let mut map = HashMap::default();
        if let Some(home_id) = p.home_id {
            map.insert("home_id", home_id.to_string());
        }
        if let Some(gateway_types) = p.gateway_types {
            let gateway_types = gateway_types
                .iter()
                .map(|x| x.to_string())
                .collect::<Vec<_>>()
                .as_slice()
                .join(",");
            map.insert("gateway_types", gateway_types);
        }

        map
    }
}

pub(crate) fn get_homes_data(client: &AuthenticatedClient, parameters: &Parameters) -> Result<HomesData> {
    let params: HashMap<&str, String> = parameters.into();
    let mut params = params.iter().map(|(k, v)| (*k, v.as_ref())).collect();
    client.call("get_homes_data", "https://api.netatmo.com/api/homesdata", &mut params)
}