use serde::{de::Deserializer, de::Error, Deserialize, Serialize};
use serde_repr::Deserialize_repr;
use std::net::IpAddr;
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct Config {
pub name: String,
#[serde(rename(deserialize = "swupdate2"))]
pub software_update: SoftwareUpdate,
#[serde(rename(deserialize = "swversion"))]
pub software_version: String,
#[serde(rename(deserialize = "apiversion"))]
pub api_version: String,
#[serde(rename(deserialize = "linkbutton"))]
pub link_button: bool,
#[serde(rename(deserialize = "ipaddress"))]
pub ip_address: IpAddr,
#[serde(rename(deserialize = "mac"))]
pub mac_address: String,
pub netmask: String,
pub gateway: IpAddr,
pub dhcp: bool,
#[serde(rename(deserialize = "portalservices"))]
pub portal_services: bool,
#[serde(rename(deserialize = "portalconnection"))]
pub portal_connection: ServiceStatus,
#[serde(rename(deserialize = "portalstate"))]
pub portal_state: PortalState,
#[serde(rename(deserialize = "internetservices"))]
pub internet_services: InternetServices,
#[serde(rename(deserialize = "UTC"))]
pub current_time: chrono::NaiveDateTime,
#[serde(rename(deserialize = "localtime"))]
#[serde(deserialize_with = "deserialize_local_time")]
pub local_time: Option<chrono::NaiveDateTime>,
#[serde(deserialize_with = "deserialize_timezone")]
pub timezone: Option<String>,
#[serde(rename(deserialize = "zigbeechannel"))]
pub zigbee_channel: u8,
#[serde(rename(deserialize = "modelid"))]
pub model_id: String,
#[serde(rename(deserialize = "bridgeid"))]
pub bridge_id: String,
#[serde(rename(deserialize = "factorynew"))]
pub factory_new: bool,
#[serde(rename(deserialize = "replacesbridgeid"))]
pub replaces_bridge_id: Option<bool>,
#[serde(rename(deserialize = "datastoreversion"))]
pub datastore_version: String,
#[serde(rename(deserialize = "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, Serialize)]
pub struct SoftwareUpdate {
pub state: SoftwareUpdateState,
#[serde(rename(deserialize = "checkforupdate"))]
pub check: bool,
#[serde(rename(deserialize = "autoinstall"))]
pub auto_install: SoftwareUpdateAutoInstall,
#[serde(rename(deserialize = "lastchange"))]
pub last_change: Option<chrono::NaiveDateTime>,
#[serde(rename(deserialize = "lastinstall"))]
pub last_install: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all(deserialize = "lowercase"))]
pub enum SoftwareUpdateState {
Unkown,
NoUpdates,
Transferring,
AnyReadyToInstall,
AllReadyToInstall,
Installing,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct SoftwareUpdateAutoInstall {
pub on: bool,
#[serde(
rename(deserialize = "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, Serialize)]
pub struct PortalState {
pub signedon: bool,
pub incoming: bool,
pub outgoing: bool,
pub communication: ServiceStatus,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct InternetServices {
pub internet: ServiceStatus,
#[serde(rename(deserialize = "remoteaccess"))]
pub remote_access: ServiceStatus,
pub time: ServiceStatus,
#[serde(rename(deserialize = "swupdate"))]
pub software_update: ServiceStatus,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all(deserialize = "lowercase"))]
pub enum ServiceStatus {
Connected,
Disconnected,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct Backup {
pub status: BackupStatus,
#[serde(rename(deserialize = "errorcode"))]
pub error: BackupError,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum BackupStatus {
#[serde(rename(deserialize = "idle"))]
Idle,
#[serde(rename(deserialize = "startmigration"))]
StartMigration,
#[serde(rename(deserialize = "fileready_disabled"))]
FilereadyDisabled,
#[serde(rename(deserialize = "prepare_restore"))]
PrepareRestore,
#[serde(rename(deserialize = "restoring"))]
Restoring,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize_repr, Serialize)]
#[repr(u8)]
pub enum BackupError {
None = 0,
ExportFailed = 1,
ImportFailed = 2,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct User {
#[serde(skip_deserializing)]
pub id: String,
pub name: String,
#[serde(rename(deserialize = "last use date"))]
pub last_use_date: chrono::NaiveDateTime,
#[serde(rename(deserialize = "create date"))]
pub create_date: chrono::NaiveDateTime,
}
impl User {
fn with_id(self, id: &str) -> Self {
Self {
id: id.to_owned(),
..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 Modifier {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn is_empty(&self) -> bool {
self.name == None
&& self.ip_address == None
&& self.netmask == None
&& self.gateway == None
&& self.dhcp == None
&& self.proxy_port == None
&& self.proxy_address == None
&& self.linkbutton == None
&& self.touchlink == None
&& self.zigbee_channel == None
&& self.current_time == None
&& self.timezone == None
}
pub fn name(self, value: &str) -> Self {
Self {
name: Some(value.to_owned()),
..self
}
}
pub fn ip_address(self, value: IpAddr) -> Self {
Self {
ip_address: Some(value),
..self
}
}
pub fn netmask(self, value: &str) -> Self {
Self {
netmask: Some(value.to_owned()),
..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(self, value: &str) -> Self {
Self {
current_time: Some(value.to_owned()),
..self
}
}
pub fn timezone(self, value: &str) -> Self {
Self {
timezone: Some(value.to_owned()),
..self
}
}
}