use serde::Serialize;
use crate::economy::Economy;
use crate::energy::Energy;
use crate::events::EventsDescription;
use crate::route::RouteConfigs;
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub enum DeviceKind {
Unknown,
Light,
}
impl DeviceKind {
const fn description(self) -> &'static str {
match self {
Self::Unknown => "Unknown",
Self::Light => "Light",
}
}
}
impl core::fmt::Display for DeviceKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.description())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub enum DeviceEnvironment {
Os,
Esp32,
}
#[derive(Debug, PartialEq, Clone, Serialize)]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct DeviceInfo {
#[serde(skip_serializing_if = "Energy::is_empty")]
#[serde(default = "Energy::empty")]
pub energy: Energy,
#[serde(skip_serializing_if = "Economy::is_empty")]
#[serde(default = "Economy::empty")]
pub economy: Economy,
}
impl DeviceInfo {
#[must_use]
pub fn empty() -> Self {
Self {
energy: Energy::empty(),
economy: Economy::empty(),
}
}
#[must_use]
pub fn add_energy(mut self, energy: Energy) -> Self {
self.energy = energy;
self
}
#[must_use]
pub fn add_economy(mut self, economy: Economy) -> Self {
self.economy = economy;
self
}
}
#[derive(Debug, PartialEq, Serialize)]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct DeviceData {
pub kind: DeviceKind,
pub environment: DeviceEnvironment,
pub description: Option<alloc::borrow::Cow<'static, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wifi_mac: Option<[u8; 6]>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ethernet_mac: Option<[u8; 6]>,
#[serde(rename = "main route")]
pub main_route: alloc::borrow::Cow<'static, str>,
pub route_configs: RouteConfigs,
pub mandatory_routes: u8,
#[serde(skip_serializing_if = "Option::is_none")]
pub events_description: Option<EventsDescription>,
}
impl DeviceData {
#[must_use]
pub fn new(
kind: DeviceKind,
environment: DeviceEnvironment,
wifi_mac: Option<[u8; 6]>,
ethernet_mac: Option<[u8; 6]>,
main_route: impl Into<alloc::borrow::Cow<'static, str>>,
route_configs: RouteConfigs,
mandatory_routes: u8,
) -> Self {
Self {
kind,
environment,
description: None,
wifi_mac,
ethernet_mac,
main_route: main_route.into(),
route_configs,
mandatory_routes,
events_description: None,
}
}
#[must_use]
pub fn description(mut self, description: impl Into<alloc::borrow::Cow<'static, str>>) -> Self {
self.description = Some(description.into());
self
}
#[must_use]
#[inline]
pub fn events_description(mut self, events_description: EventsDescription) -> Self {
self.events_description = Some(events_description);
self
}
}
#[cfg(test)]
#[cfg(feature = "deserialize")]
mod tests {
use crate::route::{Route, RouteConfigs};
use crate::economy::{Cost, CostTimespan, Costs, Economy, Roi, Rois};
use crate::energy::{
CarbonFootprint, CarbonFootprints, Energy, EnergyClass, EnergyEfficiencies,
EnergyEfficiency, WaterUseEfficiency,
};
use crate::{deserialize, serialize};
use super::{DeviceData, DeviceEnvironment, DeviceInfo, DeviceKind};
fn energy() -> Energy {
let energy_efficiencies =
EnergyEfficiencies::init(EnergyEfficiency::new(-50, EnergyClass::A))
.insert(EnergyEfficiency::new(50, EnergyClass::B));
let carbon_footprints = CarbonFootprints::init(CarbonFootprint::new(-50, EnergyClass::A))
.insert(CarbonFootprint::new(50, EnergyClass::B));
let water_use_efficiency = WaterUseEfficiency::init_with_gpp(2.5)
.penman_monteith_equation(3.2)
.wer(1.1);
Energy::init_with_energy_efficiencies(energy_efficiencies)
.carbon_footprints(carbon_footprints)
.water_use_efficiency(water_use_efficiency)
}
fn economy() -> Economy {
let costs = Costs::init(Cost::new(100, CostTimespan::Week))
.insert(Cost::new(1000, CostTimespan::Month));
let roi = Rois::init(Roi::new(10, EnergyClass::A)).insert(Roi::new(20, EnergyClass::B));
Economy::init_with_costs(costs).roi(roi)
}
fn routes() -> RouteConfigs {
RouteConfigs::init(Route::put("On", "/on").serialize_data())
.insert(Route::put("Off", "/off").serialize_data())
}
#[test]
fn test_device_kind() {
for device_kind in &[DeviceKind::Unknown, DeviceKind::Light] {
assert_eq!(
deserialize::<DeviceKind>(serialize(device_kind)),
*device_kind
);
}
}
#[test]
fn test_device_environment() {
for device_environment in &[DeviceEnvironment::Os, DeviceEnvironment::Esp32] {
assert_eq!(
deserialize::<DeviceEnvironment>(serialize(device_environment)),
*device_environment
);
}
}
#[test]
fn test_device_info() {
let mut device_info = DeviceInfo::empty();
device_info = device_info.add_energy(energy()).add_economy(economy());
assert_eq!(
deserialize::<DeviceInfo>(serialize(&device_info)),
device_info
);
}
#[test]
fn test_device_data() {
let device_data = DeviceData::new(
DeviceKind::Light,
DeviceEnvironment::Os,
None,
None,
"/light",
routes(),
2,
)
.description("A light device.");
assert_eq!(
deserialize::<DeviceData>(serialize(&device_data)),
device_data
);
}
}