use crate::capabilities::Capabilities;
use crate::command::StatusCommand;
use crate::device::Device;
use crate::error::Error;
use crate::protocol::{MqttBroker, Protocol, SharedMqttClient};
use crate::response::StatusResponse;
use crate::state::DeviceState;
#[derive(Debug)]
pub struct BrokerDeviceBuilder<'a> {
broker: &'a MqttBroker,
topic: String,
capabilities: Option<Capabilities>,
}
impl<'a> BrokerDeviceBuilder<'a> {
pub(crate) fn new(broker: &'a MqttBroker, topic: impl Into<String>) -> Self {
Self {
broker,
topic: topic.into(),
capabilities: None,
}
}
#[must_use]
pub fn with_capabilities(mut self, capabilities: Capabilities) -> Self {
self.capabilities = Some(capabilities);
self
}
pub async fn build(self) -> Result<(Device<SharedMqttClient>, DeviceState), Error> {
let client = self.create_client().await?;
let capabilities = if let Some(caps) = self.capabilities {
caps
} else {
let cmd = StatusCommand::device_parameters();
let response = client.send_command(&cmd).await.map_err(Error::Protocol)?;
let mut status: StatusResponse = response.parse().map_err(Error::Parse)?;
let cmd_state = StatusCommand::state();
if let Ok(state_response) = client.send_command(&cmd_state).await
&& let Ok(state_status) = state_response.parse::<StatusResponse>()
{
status.sensor_status = state_status.sensor_status;
}
let cmd_sensors = StatusCommand::sensors();
if let Ok(sensors_response) = client.send_command(&cmd_sensors).await
&& let Ok(sensors_status) = sensors_response.parse::<StatusResponse>()
{
status.sensors = sensors_status.sensors;
}
Capabilities::from_status(&status)
};
let device = Device::new(client, capabilities);
device.register_callbacks();
let initial_state = device.query_state().await?;
Ok((device, initial_state))
}
pub async fn build_without_probe(
self,
) -> Result<(Device<SharedMqttClient>, DeviceState), Error> {
let client = self.create_client().await?;
let capabilities = self.capabilities.unwrap_or_default();
let device = Device::new(client, capabilities);
device.register_callbacks();
let initial_state = device.query_state().await?;
Ok((device, initial_state))
}
async fn create_client(&self) -> Result<SharedMqttClient, Error> {
let (response_rx, router) = self
.broker
.add_device_subscription(self.topic.clone())
.await
.map_err(Error::Protocol)?;
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
Ok(SharedMqttClient::new(
self.broker.client().clone(),
self.topic.clone(),
response_rx,
router,
self.broker.clone(),
self.broker.command_timeout(),
))
}
}