ccs: tristar: reconnect on fail

This commit is contained in:
Alex Janka 2025-01-10 14:55:09 +11:00
parent 4f2534b5a0
commit b8c2a8c114

View file

@ -55,19 +55,38 @@ pub struct Tristar {
consecutive_errors: usize,
scaling: Scaling,
settings_last_read: Option<std::time::Instant>,
transport_settings: crate::config::Transport,
}
struct ModbusTimeout(tokio_modbus::client::Context);
struct ModbusTimeout {
context: tokio_modbus::client::Context,
reconnect_required: bool,
}
const MODBUS_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(3);
impl ModbusTimeout {
const fn new(context: tokio_modbus::client::Context) -> Self {
Self {
context,
reconnect_required: false,
}
}
pub async fn write_single_register(
&mut self,
addr: tokio_modbus::Address,
word: u16,
) -> eyre::Result<()> {
tokio::time::timeout(MODBUS_TIMEOUT, self.0.write_single_register(addr, word)).await???;
let r = tokio::time::timeout(
MODBUS_TIMEOUT,
self.context.write_single_register(addr, word),
)
.await?;
if let Err(tokio_modbus::Error::Transport(_)) = &r {
self.reconnect_required = true;
}
r??;
Ok(())
}
@ -76,9 +95,15 @@ impl ModbusTimeout {
addr: tokio_modbus::Address,
cnt: tokio_modbus::Quantity,
) -> eyre::Result<Vec<u16>> {
let v = tokio::time::timeout(MODBUS_TIMEOUT, self.0.read_holding_registers(addr, cnt))
.await???;
Ok(v)
let r = tokio::time::timeout(
MODBUS_TIMEOUT,
self.context.read_holding_registers(addr, cnt),
)
.await?;
if let Err(tokio_modbus::Error::Transport(_)) = &r {
self.reconnect_required = true;
}
Ok(r??)
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -561,27 +586,30 @@ impl ChargeStateGauges {
}
}
async fn connect_modbus(transport: &crate::config::Transport) -> eyre::Result<ModbusTimeout> {
let slave = tokio_modbus::Slave(DEVICE_ID);
let modbus = match transport {
crate::config::Transport::Serial { port, baud_rate } => {
let modbus_serial =
tokio_serial::SerialStream::open(&tokio_serial::new(port, *baud_rate))?;
tokio_modbus::client::rtu::attach_slave(modbus_serial, slave)
}
crate::config::Transport::Tcp { ip, port } => {
let modbus_tcp = tokio::net::TcpStream::connect((*ip, *port)).await?;
tokio_modbus::client::tcp::attach_slave(modbus_tcp, slave)
}
};
Ok(ModbusTimeout::new(modbus))
}
impl Tristar {
pub async fn new(
friendly_name: &str,
transport: &crate::config::Transport,
) -> eyre::Result<Self> {
let slave = tokio_modbus::Slave(DEVICE_ID);
let modbus = match transport {
crate::config::Transport::Serial { port, baud_rate } => {
let modbus_serial =
tokio_serial::SerialStream::open(&tokio_serial::new(port, *baud_rate))?;
tokio_modbus::client::rtu::attach_slave(modbus_serial, slave)
}
crate::config::Transport::Tcp { ip, port } => {
let modbus_tcp = tokio::net::TcpStream::connect((*ip, *port)).await?;
tokio_modbus::client::tcp::attach_slave(modbus_tcp, slave)
}
};
let mut modbus = ModbusTimeout(modbus);
let mut modbus = connect_modbus(transport).await?;
let scaling = {
let data = modbus.read_holding_registers(0x0000, 4).await?;
Scaling::from(&data)
@ -596,10 +624,14 @@ impl Tristar {
consecutive_errors: 0,
scaling,
settings_last_read: None,
transport_settings: transport.clone(),
})
}
pub async fn refresh(&mut self) -> eyre::Result<TristarState> {
if self.modbus.reconnect_required {
self.modbus = connect_modbus(&self.transport_settings).await?;
}
let new_state = self.get_data().await?;
self.scaling = new_state.scaling;