Skip to main content

bacnet_client/client/
cov.rs

1use super::*;
2use bacnet_services::cov::{SubscribeCOVPropertyRequest, SubscribeCOVRequest};
3use bacnet_types::enums::PropertyIdentifier;
4use bacnet_types::primitives::ObjectIdentifier;
5
6impl<T: TransportPort + 'static> BACnetClient<T> {
7    fn subscribe_cov_request(
8        subscriber_process_identifier: u32,
9        monitored_object_identifier: ObjectIdentifier,
10        confirmed: Option<bool>,
11        lifetime: Option<u32>,
12    ) -> SubscribeCOVRequest {
13        SubscribeCOVRequest {
14            subscriber_process_identifier,
15            monitored_object_identifier,
16            issue_confirmed_notifications: confirmed,
17            lifetime,
18        }
19    }
20
21    async fn send_subscribe_cov_request(
22        &self,
23        target: ConfirmedTarget<'_>,
24        request: SubscribeCOVRequest,
25    ) -> Result<(), Error> {
26        let mut buf = BytesMut::new();
27        request.encode(&mut buf);
28
29        let _ = self
30            .confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV, &buf)
31            .await?;
32
33        Ok(())
34    }
35
36    fn subscribe_cov_property_request(
37        subscriber_process_identifier: u32,
38        monitored_object_identifier: ObjectIdentifier,
39        confirmed: Option<bool>,
40        lifetime: Option<u32>,
41        monitored_property_identifier: PropertyIdentifier,
42        monitored_property_array_index: Option<u32>,
43        cov_increment: Option<f32>,
44    ) -> SubscribeCOVPropertyRequest {
45        SubscribeCOVPropertyRequest {
46            subscriber_process_identifier,
47            monitored_object_identifier,
48            issue_confirmed_notifications: confirmed,
49            lifetime,
50            monitored_property_identifier,
51            monitored_property_array_index,
52            cov_increment,
53        }
54    }
55
56    async fn send_subscribe_cov_property_request(
57        &self,
58        target: ConfirmedTarget<'_>,
59        request: SubscribeCOVPropertyRequest,
60    ) -> Result<(), Error> {
61        let mut buf = BytesMut::new();
62        request.encode(&mut buf);
63
64        let _ = self
65            .confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV_PROPERTY, &buf)
66            .await?;
67
68        Ok(())
69    }
70
71    /// Subscribe to COV notifications for an object at a directly reachable MAC address.
72    pub async fn subscribe_cov(
73        &self,
74        destination_mac: &[u8],
75        subscriber_process_identifier: u32,
76        monitored_object_identifier: ObjectIdentifier,
77        confirmed: bool,
78        lifetime: Option<u32>,
79    ) -> Result<(), Error> {
80        let request = Self::subscribe_cov_request(
81            subscriber_process_identifier,
82            monitored_object_identifier,
83            Some(confirmed),
84            lifetime,
85        );
86
87        self.send_subscribe_cov_request(
88            ConfirmedTarget::Local {
89                mac: destination_mac,
90            },
91            request,
92        )
93        .await
94    }
95
96    /// Subscribe to COV notifications for a discovered device, auto-routing if needed.
97    pub async fn subscribe_cov_to_device(
98        &self,
99        device_instance: u32,
100        subscriber_process_identifier: u32,
101        monitored_object_identifier: ObjectIdentifier,
102        confirmed: bool,
103        lifetime: Option<u32>,
104    ) -> Result<(), Error> {
105        let (mac, routing) = self.resolve_device(device_instance).await?;
106        let request = Self::subscribe_cov_request(
107            subscriber_process_identifier,
108            monitored_object_identifier,
109            Some(confirmed),
110            lifetime,
111        );
112
113        if let Some((dnet, dadr)) = routing {
114            self.send_subscribe_cov_request(
115                ConfirmedTarget::Routed {
116                    router_mac: &mac,
117                    dest_network: dnet,
118                    dest_mac: &dadr,
119                },
120                request,
121            )
122            .await
123        } else {
124            self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
125                .await
126        }
127    }
128
129    /// Cancel a COV subscription on a remote device.
130    pub async fn unsubscribe_cov(
131        &self,
132        destination_mac: &[u8],
133        subscriber_process_identifier: u32,
134        monitored_object_identifier: ObjectIdentifier,
135    ) -> Result<(), Error> {
136        let request = Self::subscribe_cov_request(
137            subscriber_process_identifier,
138            monitored_object_identifier,
139            None,
140            None,
141        );
142
143        self.send_subscribe_cov_request(
144            ConfirmedTarget::Local {
145                mac: destination_mac,
146            },
147            request,
148        )
149        .await
150    }
151
152    /// Cancel a COV subscription for a discovered device, auto-routing if needed.
153    pub async fn unsubscribe_cov_to_device(
154        &self,
155        device_instance: u32,
156        subscriber_process_identifier: u32,
157        monitored_object_identifier: ObjectIdentifier,
158    ) -> Result<(), Error> {
159        let (mac, routing) = self.resolve_device(device_instance).await?;
160        let request = Self::subscribe_cov_request(
161            subscriber_process_identifier,
162            monitored_object_identifier,
163            None,
164            None,
165        );
166
167        if let Some((dnet, dadr)) = routing {
168            self.send_subscribe_cov_request(
169                ConfirmedTarget::Routed {
170                    router_mac: &mac,
171                    dest_network: dnet,
172                    dest_mac: &dadr,
173                },
174                request,
175            )
176            .await
177        } else {
178            self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
179                .await
180        }
181    }
182
183    /// Subscribe to COV notifications for a single property at a directly reachable MAC address.
184    pub async fn subscribe_cov_property(
185        &self,
186        destination_mac: &[u8],
187        subscriber_process_identifier: u32,
188        monitored_object_identifier: ObjectIdentifier,
189        monitored_property_identifier: PropertyIdentifier,
190        monitored_property_array_index: Option<u32>,
191        confirmed: bool,
192        lifetime: Option<u32>,
193        cov_increment: Option<f32>,
194    ) -> Result<(), Error> {
195        let request = Self::subscribe_cov_property_request(
196            subscriber_process_identifier,
197            monitored_object_identifier,
198            Some(confirmed),
199            lifetime,
200            monitored_property_identifier,
201            monitored_property_array_index,
202            cov_increment,
203        );
204
205        self.send_subscribe_cov_property_request(
206            ConfirmedTarget::Local {
207                mac: destination_mac,
208            },
209            request,
210        )
211        .await
212    }
213
214    /// Subscribe to COV notifications for a single property on a discovered device,
215    /// auto-routing if needed.
216    pub async fn subscribe_cov_property_to_device(
217        &self,
218        device_instance: u32,
219        subscriber_process_identifier: u32,
220        monitored_object_identifier: ObjectIdentifier,
221        monitored_property_identifier: PropertyIdentifier,
222        monitored_property_array_index: Option<u32>,
223        confirmed: bool,
224        lifetime: Option<u32>,
225        cov_increment: Option<f32>,
226    ) -> Result<(), Error> {
227        let (mac, routing) = self.resolve_device(device_instance).await?;
228        let request = Self::subscribe_cov_property_request(
229            subscriber_process_identifier,
230            monitored_object_identifier,
231            Some(confirmed),
232            lifetime,
233            monitored_property_identifier,
234            monitored_property_array_index,
235            cov_increment,
236        );
237
238        if let Some((dnet, dadr)) = routing {
239            self.send_subscribe_cov_property_request(
240                ConfirmedTarget::Routed {
241                    router_mac: &mac,
242                    dest_network: dnet,
243                    dest_mac: &dadr,
244                },
245                request,
246            )
247            .await
248        } else {
249            self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
250                .await
251        }
252    }
253
254    /// Cancel a single-property COV subscription at a directly reachable MAC address.
255    pub async fn unsubscribe_cov_property(
256        &self,
257        destination_mac: &[u8],
258        subscriber_process_identifier: u32,
259        monitored_object_identifier: ObjectIdentifier,
260        monitored_property_identifier: PropertyIdentifier,
261        monitored_property_array_index: Option<u32>,
262    ) -> Result<(), Error> {
263        let request = Self::subscribe_cov_property_request(
264            subscriber_process_identifier,
265            monitored_object_identifier,
266            None,
267            None,
268            monitored_property_identifier,
269            monitored_property_array_index,
270            None,
271        );
272
273        self.send_subscribe_cov_property_request(
274            ConfirmedTarget::Local {
275                mac: destination_mac,
276            },
277            request,
278        )
279        .await
280    }
281
282    /// Cancel a single-property COV subscription for a discovered device,
283    /// auto-routing if needed.
284    pub async fn unsubscribe_cov_property_to_device(
285        &self,
286        device_instance: u32,
287        subscriber_process_identifier: u32,
288        monitored_object_identifier: ObjectIdentifier,
289        monitored_property_identifier: PropertyIdentifier,
290        monitored_property_array_index: Option<u32>,
291    ) -> Result<(), Error> {
292        let (mac, routing) = self.resolve_device(device_instance).await?;
293        let request = Self::subscribe_cov_property_request(
294            subscriber_process_identifier,
295            monitored_object_identifier,
296            None,
297            None,
298            monitored_property_identifier,
299            monitored_property_array_index,
300            None,
301        );
302
303        if let Some((dnet, dadr)) = routing {
304            self.send_subscribe_cov_property_request(
305                ConfirmedTarget::Routed {
306                    router_mac: &mac,
307                    dest_network: dnet,
308                    dest_mac: &dadr,
309                },
310                request,
311            )
312            .await
313        } else {
314            self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
315                .await
316        }
317    }
318
319    /// Get a receiver for incoming COV notifications. Each call returns a new
320    /// independent receiver.
321    pub fn cov_notifications(&self) -> broadcast::Receiver<ReceivedCOVNotification> {
322        self.cov_tx.subscribe()
323    }
324}