#![allow(dead_code)]
use log::debug;
use log::warn;
use noise_protocol::CipherState;
use noise_protocol::HandshakeState;
use noise_rust_crypto::ChaCha20Poly1305;
use noise_rust_crypto::Sha256;
use noise_rust_crypto::X25519;
use std::collections::HashMap;
use std::str;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use tokio::net::TcpStream;
use tokio::sync::Mutex;
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::RecvError;
use typed_builder::TypedBuilder;
use crate::connection::Connection;
use crate::error::Error;
use crate::esphomeapi::EspHomeApi;
use crate::parser::ProtoMessage;
use crate::proto::ListEntitiesDoneResponse;
#[derive(TypedBuilder)]
pub struct EspHomeServer {
#[builder(default=HashMap::new(), setter(skip))]
pub(crate) components_by_key: HashMap<u32, Entity>,
#[builder(default=HashMap::new(), setter(skip))]
pub(crate) components_key_id: HashMap<String, u32>,
#[builder(default = 0, setter(skip))]
pub(crate) current_key: u32,
#[builder(via_mutators, default=Arc::new(AtomicBool::new(false)))]
pub(crate) encrypted_api: Arc<AtomicBool>,
#[builder(via_mutators)]
pub(crate) noise_psk: Vec<u8>,
#[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
pub(crate) handshake_state:
Arc<Mutex<Option<HandshakeState<X25519, ChaCha20Poly1305, Sha256>>>>,
#[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
pub(crate) encrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
#[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
pub(crate) decrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
name: String,
#[builder(default = None, setter(strip_option))]
#[deprecated(note = "https://esphome.io/components/api.html#configuration-variables")]
password: Option<String>,
#[builder(default = None, setter(strip_option))]
encryption_key: Option<String>,
#[builder(default = 1)]
api_version_major: u32,
#[builder(default = 10)]
api_version_minor: u32,
#[builder(default="Rust: esphome-native-api".to_string())]
server_info: String,
#[builder(default = None, setter(strip_option))]
friendly_name: Option<String>,
#[builder(default = None, setter(strip_option))]
mac: Option<String>,
#[builder(default = None, setter(strip_option))]
model: Option<String>,
#[builder(default = None, setter(strip_option))]
manufacturer: Option<String>,
#[builder(default = None, setter(strip_option))]
suggested_area: Option<String>,
#[builder(default = None, setter(strip_option))]
bluetooth_mac_address: Option<String>,
}
impl EspHomeServer {
pub async fn start(&mut self, tcp_stream: TcpStream) -> Result<Connection, Error> {
let server = EspHomeApi::builder()
.api_version_major(self.api_version_major)
.api_version_minor(self.api_version_minor)
.server_info(self.server_info.clone())
.name(self.name.clone())
.build()?;
let api_connection = server.start(tcp_stream).await?;
let messages_tx = api_connection.sender();
let mut messages_rx = api_connection.receiver();
let (outgoing_messages_tx, outgoing_messages_rx) = broadcast::channel::<ProtoMessage>(16);
let (done_tx, done_rx) = tokio::sync::oneshot::channel::<Result<(), Error>>();
let api_components_clone = self.components_by_key.clone();
tokio::spawn(async move {
loop {
let message = match messages_rx.recv().await {
Ok(message) => message,
Err(RecvError::Lagged(skipped)) => {
warn!("Message routing lagged, {skipped} messages skipped");
continue;
}
Err(RecvError::Closed) => break,
};
debug!("Received message: {:?}", message);
match message {
ProtoMessage::ListEntitiesRequest(list_entities_request) => {
debug!("ListEntitiesRequest: {:?}", list_entities_request);
for _sensor in api_components_clone.values() {
}
let _ = outgoing_messages_tx.send(ProtoMessage::ListEntitiesDoneResponse(
ListEntitiesDoneResponse {},
));
}
other_message => {
let _ = outgoing_messages_tx.send(other_message);
}
}
}
let _ = done_tx.send(api_connection.wait().await);
});
Ok(Connection::new(messages_tx, outgoing_messages_rx, done_rx))
}
pub fn add_entity(&mut self, entity_id: &str, entity: Entity) {
self.components_key_id
.insert(entity_id.to_string(), self.current_key);
self.components_by_key.insert(self.current_key, entity);
self.current_key += 1;
}
}
#[derive(Clone, Debug)]
pub enum Entity {
BinarySensor(BinarySensor),
}
#[derive(Clone, Debug)]
pub struct BinarySensor {
pub object_id: String,
}