use le_stream::ToLeStream;
use log::trace;
use tokio::sync::mpsc::Sender;
use tokio::sync::oneshot::channel;
use zb_core::destination::Device;
use zb_core::{ClusterSpecific, Destination, ExpectResponse, Profiled};
use zb_zcl::{Cluster, Command, Directed};
use crate::zcl::{Message, Payload};
use crate::{CommunicationResponse, Coordinator, Error, TransmissionResponse};
pub type ZclResponse<T> = CommunicationResponse<Cluster, T>;
pub trait Zcl {
fn transmit<T>(
&self,
destination: Destination,
payload: T,
) -> impl Future<Output = Result<TransmissionResponse, Error>> + Send
where
T: ClusterSpecific + Command + Directed + Profiled + ToLeStream;
fn communicate<T>(
&self,
destination: Device,
payload: T,
) -> impl Future<Output = Result<ZclResponse<T::Response>, Error>> + Send
where
T: ExpectResponse<Cluster> + Into<Payload>;
}
impl Zcl for Sender<Message> {
fn transmit<T>(
&self,
destination: Destination,
payload: T,
) -> impl Future<Output = Result<TransmissionResponse, Error>> + Send
where
T: ClusterSpecific + Command + Directed + Profiled + ToLeStream,
{
let payload = payload.into();
let (response, result) = channel();
trace!("Sending unicast message to {destination} with payload: {payload:?}");
async move {
self.send(Message::Transmit {
destination,
payload,
response,
})
.await?;
Ok(result.await??.into())
}
}
fn communicate<T>(
&self,
device: Device,
payload: T,
) -> impl Future<Output = Result<ZclResponse<T::Response>, Error>> + Send
where
T: ExpectResponse<Cluster> + Into<Payload>,
{
let payload = payload.into();
let (response, result) = channel();
async move {
self.send(Message::Communicate {
device,
payload,
response,
})
.await?;
Ok(result.await??.into())
}
}
}
impl Zcl for Coordinator {
fn transmit<T>(
&self,
destination: Destination,
payload: T,
) -> impl Future<Output = Result<TransmissionResponse, Error>> + Send
where
T: ClusterSpecific + Command + Directed + Profiled + ToLeStream,
{
self.zcl.transmit(destination, payload)
}
fn communicate<T>(
&self,
destination: Device,
payload: T,
) -> impl Future<Output = Result<ZclResponse<T::Response>, Error>> + Send
where
T: ExpectResponse<Cluster> + Into<Payload>,
{
self.zcl.communicate(destination, payload)
}
}