esphome_native_api/
esphomeserver.rs

1use crate::esphomeapi::EspHomeApi;
2use crate::parser::ProtoMessage;
3
4use crate::proto::version_2025_12_1::ListEntitiesDoneResponse;
5use log::debug;
6use log::error;
7use log::info;
8use log::trace;
9use noise_protocol::CipherState;
10use noise_protocol::HandshakeState;
11use noise_rust_crypto::ChaCha20Poly1305;
12use noise_rust_crypto::Sha256;
13use noise_rust_crypto::X25519;
14use std::collections::HashMap;
15use std::str;
16use std::sync::Arc;
17use std::sync::atomic::AtomicBool;
18use tokio::net::TcpStream;
19use tokio::sync::Mutex;
20use tokio::sync::broadcast;
21use typed_builder::TypedBuilder;
22
23#[derive(TypedBuilder)]
24pub struct EspHomeServer {
25    // Private fields
26    #[builder(default=HashMap::new(), setter(skip))]
27    pub(crate) components_by_key: HashMap<u32, Entity>,
28    #[builder(default=HashMap::new(), setter(skip))]
29    pub(crate) components_key_id: HashMap<String, u32>,
30    #[builder(default = 0, setter(skip))]
31    pub(crate) current_key: u32,
32
33    #[builder(via_mutators, default=Arc::new(AtomicBool::new(false)))]
34    pub(crate) encrypted_api: Arc<AtomicBool>,
35
36    #[builder(via_mutators)]
37    pub(crate) noise_psk: Vec<u8>,
38
39    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
40    pub(crate) handshake_state:
41        Arc<Mutex<Option<HandshakeState<X25519, ChaCha20Poly1305, Sha256>>>>,
42    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
43    pub(crate) encrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
44    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
45    pub(crate) decrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
46
47    name: String,
48
49    #[builder(default = None, setter(strip_option))]
50    #[deprecated(note = "https://esphome.io/components/api.html#configuration-variables")]
51    password: Option<String>,
52    #[builder(default = None, setter(strip_option))]
53    encryption_key: Option<String>,
54
55    #[builder(default = 1)]
56    api_version_major: u32,
57    #[builder(default = 10)]
58    api_version_minor: u32,
59    #[builder(default="Rust: esphome-native-api".to_string())]
60    server_info: String,
61
62    #[builder(default = None, setter(strip_option))]
63    friendly_name: Option<String>,
64
65    #[builder(default = None, setter(strip_option))]
66    mac: Option<String>,
67
68    #[builder(default = None, setter(strip_option))]
69    model: Option<String>,
70
71    #[builder(default = None, setter(strip_option))]
72    manufacturer: Option<String>,
73    #[builder(default = None, setter(strip_option))]
74    suggested_area: Option<String>,
75    #[builder(default = None, setter(strip_option))]
76    bluetooth_mac_address: Option<String>,
77}
78
79
80
81impl EspHomeServer {
82    /// Easier Version of the api abstraction
83    /// Handles:
84    /// - internal entity key management
85
86    pub async fn start(
87        &mut self,
88        tcp_stream: TcpStream,
89    ) -> Result<(broadcast::Sender<ProtoMessage>, broadcast::Receiver<ProtoMessage>), Box<dyn std::error::Error>> {
90        let mut server = EspHomeApi::builder()
91            .api_version_major(self.api_version_major)
92            .api_version_minor(self.api_version_minor)
93            // .password(self.password.or_else())
94            .server_info(self.server_info.clone())
95            .name(self.name.clone())
96            // .friendly_name(self.friendly_name)
97            // .bluetooth_mac_address(self.bluetooth_mac_address)
98            // .mac(self.mac)
99            // .manufacturer(self.manufacturer)
100            // .model(self.model)
101            // .suggested_area(self.suggested_area)
102            .build();
103        let (messages_tx, mut messages_rx) = server.start(tcp_stream).await?;
104        let (outgoing_messages_tx, mut outgoing_messages_rx) = broadcast::channel::<ProtoMessage>(16);
105        let api_components_clone = self.components_by_key.clone();
106        let messages_tx_clone = messages_tx.clone();
107
108        tokio::spawn(async move {
109            loop {
110                messages_rx.recv().await.map_or_else(
111                    |e| {
112                        error!("Error receiving message: {:?}", e);
113                        // Handle the error, maybe log it or break the loop
114                    },
115                    |message| {
116                        // Process the received message
117                        debug!("Received message: {:?}", message);
118
119                        match message {
120                            ProtoMessage::ListEntitiesRequest(list_entities_request) => {
121                            debug!("ListEntitiesRequest: {:?}", list_entities_request);
122
123                            for (key, sensor) in &api_components_clone {    
124                                // TODO: Handle the different entity types
125                                // outgoing_messages_tx.send(sensor.clone()).unwrap();
126                            }
127                            outgoing_messages_tx
128                                .send(ProtoMessage::ListEntitiesDoneResponse(
129                                    ListEntitiesDoneResponse {},
130                                ))
131                                .unwrap();
132                            }
133                            other_message => {
134                                // Forward the message to the outgoing channel
135                                if let Err(e) = outgoing_messages_tx.send(other_message) {
136                                    error!("Error sending message to outgoing channel: {:?}", e);
137                                }
138                            }
139                        }
140                        
141                    },
142                );
143            }
144        
145        });
146
147
148        Ok((messages_tx.clone(), outgoing_messages_rx))
149    }
150
151    pub fn add_entity(&mut self, entity_id: &str, entity: Entity) {
152        self.components_key_id
153            .insert(entity_id.to_string(), self.current_key);
154        self.components_by_key.insert(self.current_key, entity);
155
156        self.current_key += 1;
157    }
158}
159
160#[derive(Clone, Debug)]
161pub enum Entity {
162    BinarySensor(BinarySensor),
163}
164
165#[derive(Clone, Debug)]
166pub struct BinarySensor {
167    pub object_id: String,
168}
169