homeassistant_agent/model/
discovery.rs1use crate::{model::Device, utils::is_default};
2
3#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
7#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
8pub struct Discovery {
9 #[serde(default)]
12 pub name: Option<String>,
13
14 #[serde(default, skip_serializing_if = "Option::is_none")]
15 pub unique_id: Option<String>,
16
17 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub device: Option<Device>,
19
20 #[serde(default)]
22 pub device_class: Option<String>,
23
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub state_class: Option<StateClass>,
26
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub command_topic: Option<String>,
29
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub command_template: Option<String>,
32
33 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub state_topic: Option<String>,
35
36 #[serde(default, skip_serializing_if = "Option::is_none")]
37 pub unit_of_measurement: Option<String>,
38
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub value_template: Option<String>,
41
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub enabled_by_default: Option<bool>,
44
45 #[serde(default, skip_serializing_if = "is_default")]
46 pub availability_mode: AvailabilityMode,
47
48 #[serde(default, skip_serializing_if = "Vec::is_empty")]
49 pub availability: Vec<Availability>,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
53#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
54pub struct Availability {
55 pub topic: String,
56
57 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub payload_available: Option<String>,
59
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub payload_not_available: Option<String>,
62
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub value_template: Option<String>,
65}
66
67impl Availability {
68 pub fn new(topic: impl Into<String>) -> Self {
69 Self {
70 topic: topic.into(),
71 payload_available: None,
72 payload_not_available: None,
73 value_template: None,
74 }
75 }
76
77 pub fn payload_available(mut self, payload: impl Into<String>) -> Self {
78 self.payload_available = Some(payload.into());
79 self
80 }
81
82 pub fn payload_not_available(mut self, payload: impl Into<String>) -> Self {
83 self.payload_not_available = Some(payload.into());
84 self
85 }
86
87 pub fn value_template(mut self, value_template: impl Into<String>) -> Self {
88 self.value_template = Some(value_template.into());
89 self
90 }
91}
92
93#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
94#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
95#[serde(rename_all = "snake_case")]
96pub enum AvailabilityMode {
97 All,
98 Any,
99 #[default]
100 Latest,
101}
102
103#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
104#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
105#[serde(rename_all = "snake_case")]
106pub enum StateClass {
107 Measurement,
108 Total,
109 TotalIncreasing,
110}
111
112#[cfg(test)]
113mod test {
114 use super::*;
115 use serde_json::json;
116
117 #[test]
118 fn test_serde() {
119 assert_eq!(
120 serde_json::to_value(Discovery {
121 device: Some(Device {
122 identifiers: vec!["test-id1".into()],
123 name: Some("Test Device 1".to_string()),
124 base_topic: None,
125 sw_version: None,
126 support_url: None,
127 }),
128 device_class: Some("motion".to_string()),
129 state_topic: Some("some/topic".to_string()),
130 ..Default::default()
131 })
132 .unwrap(),
133 json!({
134 "name": null,
135 "device_class": "motion",
136 "device": {
137 "identifiers" : [
138 "test-id1"
139 ],
140 "name": "Test Device 1",
141 },
142 "state_topic": "some/topic"
143 })
144 )
145 }
146}