r4dcb08_lib/tokio_async_safe_client.rs
1//! Asynchronous `tokio-modbus` client for the R4DCB08 temperature module.
2//!
3//! This module provides a high-level API (`SafeClient` struct) to interact with
4//! the R4DCB08 8-channel temperature module using Modbus RTU or TCP. It handles
5//! the conversion between Rust types defined in the `crate::protocol` module and
6//! the raw Modbus register values.
7//!
8//! All client methods are `async` and must be `.await`ed.
9//!
10//! ## Example
11//!
12//! ```no_run
13//! use r4dcb08_lib::{
14//! protocol::Address,
15//! tokio_async_safe_client::SafeClient,
16//! };
17//! use tokio_modbus::client::tcp;
18//! use tokio_modbus::Slave;
19//!
20//! #[tokio::main]
21//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
22//! // Connect to the device and create a stateful, safe client
23//! let socket_addr = "192.168.1.100:502".parse()?;
24//! let ctx = tcp::connect_slave(socket_addr, Slave(*Address::default())).await?;
25//! let client = SafeClient::new(ctx);
26//!
27//! // Use the client to interact with the device
28//! let temperatures = client.read_temperatures().await?;
29//!
30//! println!("Successfully read temperatures. Current values: {}", temperatures);
31//!
32//! Ok(())
33//! }
34//! ```
35
36use crate::{protocol as proto, tokio_async, tokio_common::Result};
37use std::sync::Arc;
38use tokio::sync::Mutex;
39use tokio_modbus::{client::Context, prelude::*};
40
41/// Asynchronous client for interacting with the R4DCB08 temperature module over Modbus.
42///
43/// This struct provides methods to read sensor data and configure the module's
44/// operational parameters by wrapping `tokio-modbus` asynchronous operations.
45///
46/// All methods that interact with the Modbus device are `async` and return `Future`s.
47#[derive(Clone)]
48pub struct SafeClient {
49 ctx: Arc<Mutex<Context>>,
50}
51
52impl SafeClient {
53 /// Creates a new `SafeClient` with a given `tokio-modbus` asynchronous context.
54 pub fn new(ctx: Context) -> Self {
55 Self {
56 ctx: Arc::new(Mutex::new(ctx)),
57 }
58 }
59
60 /// Creates a new `SafeClient` from a shared `tokio-modbus` asynchronous context.
61 pub fn from_shared(ctx: Arc<Mutex<Context>>) -> Self {
62 Self { ctx }
63 }
64
65 /// Clones the shared `tokio-modbus` asynchronous context.
66 pub fn clone_shared(&self) -> Arc<Mutex<Context>> {
67 self.ctx.clone()
68 }
69
70 /// Reads the current temperatures from all 8 available channels in degrees Celsius (°C).
71 pub async fn read_temperatures(&self) -> Result<proto::Temperatures> {
72 let mut ctx = self.ctx.lock().await;
73 tokio_async::R4DCB08::read_temperatures(&mut ctx).await
74 }
75
76 /// Reads the configured temperature correction values (°C) for all 8 channels.
77 pub async fn read_temperature_correction(&self) -> Result<proto::TemperatureCorrection> {
78 let mut ctx = self.ctx.lock().await;
79 tokio_async::R4DCB08::read_temperature_correction(&mut ctx).await
80 }
81
82 /// Sets a temperature correction value for a specific channel.
83 pub async fn set_temperature_correction(
84 &self,
85 channel: proto::Channel,
86 correction: proto::Temperature,
87 ) -> Result<()> {
88 let mut ctx = self.ctx.lock().await;
89 tokio_async::R4DCB08::set_temperature_correction(&mut ctx, channel, correction).await
90 }
91
92 /// Reads the automatic temperature reporting interval.
93 pub async fn read_automatic_report(&self) -> Result<proto::AutomaticReport> {
94 let mut ctx = self.ctx.lock().await;
95 tokio_async::R4DCB08::read_automatic_report(&mut ctx).await
96 }
97
98 /// Sets the automatic temperature reporting interval.
99 pub async fn set_automatic_report(&self, report: proto::AutomaticReport) -> Result<()> {
100 let mut ctx = self.ctx.lock().await;
101 tokio_async::R4DCB08::set_automatic_report(&mut ctx, report).await
102 }
103
104 /// Reads the current Modbus communication baud rate setting from the device.
105 pub async fn read_baud_rate(&self) -> Result<proto::BaudRate> {
106 let mut ctx = self.ctx.lock().await;
107 tokio_async::R4DCB08::read_baud_rate(&mut ctx).await
108 }
109
110 /// Sets the Modbus communication baud rate for the device.
111 pub async fn set_baud_rate(&self, baud_rate: proto::BaudRate) -> Result<()> {
112 let mut ctx = self.ctx.lock().await;
113 tokio_async::R4DCB08::set_baud_rate(&mut ctx, baud_rate).await
114 }
115
116 /// Resets the R4DCB08 module to its factory default settings.
117 pub async fn factory_reset(&self) -> Result<()> {
118 let mut ctx = self.ctx.lock().await;
119 tokio_async::R4DCB08::factory_reset(&mut ctx).await
120 }
121
122 /// Reads the current Modbus device address (Slave ID) from the module.
123 pub async fn read_address(&self) -> Result<proto::Address> {
124 let mut ctx = self.ctx.lock().await;
125 tokio_async::R4DCB08::read_address(&mut ctx).await
126 }
127
128 /// Sets a new Modbus device address.
129 ///
130 /// A successful call makes the existing `Context` invalid (as it
131 /// still points to the old address). This function automatically
132 /// updates the slave ID within its managed `Context`.
133 pub async fn set_address(&self, new_address: proto::Address) -> Result<()> {
134 let mut ctx = self.ctx.lock().await;
135 tokio_async::R4DCB08::set_address(&mut ctx, new_address).await?;
136 ctx.set_slave(Slave(*new_address));
137 Ok(())
138 }
139}