use serde::{de::Deserializer, de::Error, Deserialize, Serialize};
use serde_repr::Deserialize_repr;
use std::net::IpAddr;
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct Config {
pub name: String,
#[serde(rename = "swupdate2")]
pub software_update: SoftwareUpdate,
#[serde(rename = "swversion")]
pub software_version: String,
#[serde(rename = "apiversion")]
pub api_version: String,
#[serde(rename = "linkbutton")]
pub link_button: bool,
#[serde(rename = "ipaddress")]
pub ip_address: IpAddr,
#[serde(rename = "mac")]
pub mac_address: String,
pub netmask: String,
pub gateway: IpAddr,
pub dhcp: bool,
#[serde(rename = "portalservices")]
pub portal_services: bool,
#[serde(rename = "portalconnection")]
pub portal_connection: ServiceStatus,
#[serde(rename = "portalstate")]
pub portal_state: PortalState,
#[serde(rename = "internetservices")]
pub internet_services: InternetServices,
#[serde(rename = "UTC")]
pub current_time: chrono::NaiveDateTime,
#[serde(rename = "localtime")]
#[serde(deserialize_with = "deserialize_local_time")]
pub local_time: Option<chrono::NaiveDateTime>,
#[serde(deserialize_with = "deserialize_timezone")]
pub timezone: Option<String>,
#[serde(rename = "zigbeechannel")]
pub zigbee_channel: u8,
#[serde(rename = "modelid")]
pub model_id: String,
#[serde(rename = "bridgeid")]
pub bridge_id: String,
#[serde(rename = "factorynew")]
pub factory_new: bool,
#[serde(rename = "replacesbridgeid")]
pub replaces_bridge_id: Option<bool>,
#[serde(rename = "datastoreversion")]
pub datastore_version: String,
#[serde(rename = "starterkitid")]
pub starterkit_id: String,
pub backup: Backup,
#[serde(deserialize_with = "deserialize_whitelist")]
pub whitelist: Vec<User>,
}
fn deserialize_timezone<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<String>, D::Error> {
let value: String = Deserialize::deserialize(deserializer)?;
Ok(match value.as_ref() {
"none" => None,
_ => Some(value),
})
}
fn deserialize_local_time<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<chrono::NaiveDateTime>, D::Error> {
use std::str::FromStr;
let value: String = Deserialize::deserialize(deserializer)?;
Ok(match value.as_ref() {
"none" => None,
_ => Some(chrono::NaiveDateTime::from_str(&value).map_err(D::Error::custom)?),
})
}
fn deserialize_whitelist<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<User>, D::Error> {
let map: std::collections::HashMap<String, User> = Deserialize::deserialize(deserializer)?;
let mut users = Vec::new();
for (id, user) in map {
users.push(user.with_id(&id));
}
Ok(users)
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct SoftwareUpdate {
pub state: SoftwareUpdateState,
#[serde(rename = "checkforupdate")]
pub check: bool,
#[serde(rename = "autoinstall")]
pub auto_install: SoftwareUpdateAutoInstall,
#[serde(rename = "lastchange")]
pub last_change: Option<chrono::NaiveDateTime>,
#[serde(rename = "lastinstall")]
pub last_install: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SoftwareUpdateState {
Unkown,
NoUpdates,
Transferring,
AnyReadyToInstall,
AllReadyToInstall,
Installing,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct SoftwareUpdateAutoInstall {
pub on: bool,
#[serde(rename = "updatetime", deserialize_with = "deserialize_update_time")]
pub update_time: Option<chrono::NaiveTime>,
}
fn deserialize_update_time<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<chrono::NaiveTime>, D::Error> {
use std::str::FromStr;
let mut value: String = Deserialize::deserialize(deserializer)?;
Ok(match value.remove(0) {
'T' => Some(chrono::NaiveTime::from_str(&value).map_err(D::Error::custom)?),
_ => None,
})
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct PortalState {
pub signedon: bool,
pub incoming: bool,
pub outgoing: bool,
pub communication: ServiceStatus,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct InternetServices {
pub internet: ServiceStatus,
#[serde(rename = "remoteaccess")]
pub remote_access: ServiceStatus,
pub time: ServiceStatus,
#[serde(rename = "swupdate")]
pub software_update: ServiceStatus,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ServiceStatus {
Connected,
Disconnected,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct Backup {
pub status: BackupStatus,
#[serde(rename = "errorcode")]
pub error: BackupError,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub enum BackupStatus {
#[serde(rename = "idle")]
Idle,
#[serde(rename = "startmigration")]
StartMigration,
#[serde(rename = "fileready_disabled")]
FilereadyDisabled,
#[serde(rename = "prepare_restore")]
PrepareRestore,
#[serde(rename = "restoring")]
Restoring,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize_repr)]
#[repr(u8)]
pub enum BackupError {
None = 0,
ExportFailed = 1,
ImportFailed = 2,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct User {
#[serde(skip)]
pub id: String,
pub name: String,
#[serde(rename = "last use date")]
pub last_use_date: chrono::NaiveDateTime,
#[serde(rename = "create date")]
pub create_date: chrono::NaiveDateTime,
}
impl User {
fn with_id<S: Into<String>>(self, id: S) -> Self {
Self {
id: id.into(),
..self
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct Modifier {
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "ipaddress")]
ip_address: Option<IpAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
netmask: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
gateway: Option<IpAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
dhcp: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "proxyport")]
proxy_port: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none", rename = "proxyaddress")]
proxy_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
linkbutton: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
touchlink: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "zigbeechannel")]
zigbee_channel: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none", rename = "UTC")]
current_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
timezone: Option<String>,
}
impl crate::Modifier for Modifier {}
impl Modifier {
pub fn name<S: Into<String>>(self, value: S) -> Self {
Self {
name: Some(value.into()),
..self
}
}
pub fn ip_address(self, value: IpAddr) -> Self {
Self {
ip_address: Some(value),
..self
}
}
pub fn netmask<S: Into<String>>(self, value: S) -> Self {
Self {
netmask: Some(value.into()),
..self
}
}
pub fn gateway(self, value: IpAddr) -> Self {
Self {
gateway: Some(value),
..self
}
}
pub fn dhcp(self, value: bool) -> Self {
Self {
dhcp: Some(value),
..self
}
}
pub fn proxy_port(self, value: u16) -> Self {
Self {
proxy_port: Some(value),
..self
}
}
pub fn proxy_address(self, value: Option<IpAddr>) -> Self {
Self {
proxy_address: Some(match value {
Some(v) => v.to_string(),
None => "none".to_owned(),
}),
..self
}
}
pub fn linkbutton(self, value: bool) -> Self {
Self {
linkbutton: Some(value),
..self
}
}
pub fn touchlink(self) -> Self {
Self {
touchlink: Some(true),
..self
}
}
pub fn zigbee_channel(self, value: u8) -> Self {
Self {
zigbee_channel: Some(value),
..self
}
}
pub fn current_time<S: Into<String>>(self, value: S) -> Self {
Self {
current_time: Some(value.into()),
..self
}
}
pub fn timezone<S: Into<String>>(self, value: S) -> Self {
Self {
timezone: Some(value.into()),
..self
}
}
}