netatmo-rs 0.5.0

Simple library to talk to Netatmo's API
Documentation
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)
}