From 459b97d95c46c5cf3b50c71cc343953f1a405ca6 Mon Sep 17 00:00:00 2001 From: Eric Neuber Date: Mon, 16 Feb 2026 22:33:27 +0100 Subject: [PATCH] Modbus Werte werden nun ausgelesen --- Cargo.lock | 24 +++++++++++ Cargo.toml | 1 + paramod.yaml | 14 ++----- src/modbus.rs | 108 ++++++++++++++++++++++++++++++++------------------ 4 files changed, 99 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a6535c..43c1bff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,6 +355,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.0" @@ -688,6 +694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", @@ -1732,6 +1739,7 @@ dependencies = [ "serde_yaml", "tera", "tokio", + "tokio-modbus", "toml", ] @@ -1835,6 +1843,22 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-modbus" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dfb1a3265ca939b7a76103c89ad770f8cc0ea8de76c83d352e7c1fc5b2c8b" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "futures-util", + "log", + "smallvec", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-util" version = "0.7.17" diff --git a/Cargo.toml b/Cargo.toml index 1ac73a2..990de34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ tera = "1.19" config = "0.14" toml = "0.8" serde_derive = "1.0" +tokio-modbus = "0.7" diff --git a/paramod.yaml b/paramod.yaml index ea7f4c6..00d6e30 100644 --- a/paramod.yaml +++ b/paramod.yaml @@ -1,14 +1,12 @@ default: loglevel: DEBUG - darkmode: false - + darkmode: true mqtt: broker: 192.168.178.2 - button_circulation: zigbee2mqtt/WirelessButton - password: 97sm3pHNSMZ4M5qUj0x8 port: 1883 user: admin - + password: 97sm3pHNSMZ4M5qUj0x8 + button_circulation: zigbee2mqtt/WirelessButton influxdb: bucket: Paradigma location: Radebeul @@ -16,14 +14,12 @@ influxdb: org: skaville token: i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ== url: 192.168.178.2:8086 - modbus: host: 192.168.178.10 + port: 502 max_coils_addr: 8 max_holding_addr: 61 max_input_addr: 45 - port: 502 - modbus_coils: - MgtSystem: {addr: 0, write: false, mqtt: false, influxdb: false, comment: Leitsystem aktiv} - HK1pres: {addr: 1, write: false, mqtt: false, influxdb: false, comment: HK1 vorhanden} @@ -34,7 +30,6 @@ modbus_coils: - Zrelease: {addr: 6, write: true, mqtt: false, influxdb: false, comment: Zirkulation freigegeben} - Zlock: {addr: 7, write: true, mqtt: false, influxdb: false, comment: Zirkulation gesperrt} - SHKpres: {addr: 8, write: false, mqtt: false, influxdb: false, comment: Schwimmbadheizkrei vorhanden} - modbus_input_register: - TA: {addr: 0, type: INT16, factor: 0.1, mqtt: true, influxdb: true} - TV: {addr: 1, type: INT16, factor: 0.1, mqtt: false, influxdb: true} @@ -81,7 +76,6 @@ modbus_input_register: - TKW: {addr: 42, type: INT16, factor: 0.1, mqtt: false, influxdb: true} - VKW: {addr: 43, type: INT16, factor: 0.1, mqtt: false, influxdb: true} - VSPm: {addr: 44, type: INT16, factor: 0.1, mqtt: false, influxdb: true} - modbus_holding_register: - nothing: {addr: 0, type: UINT16, factor: 1, mqtt: false, influxdb: false} - ErrLS: {addr: 1, type: UINT16, factor: 1, mqtt: false, influxdb: true} diff --git a/src/modbus.rs b/src/modbus.rs index 02621d1..9be5f9f 100644 --- a/src/modbus.rs +++ b/src/modbus.rs @@ -5,63 +5,95 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; +use tokio_modbus::prelude::*; +use tokio_modbus::client::tcp; +use std::net::SocketAddr; + /// Startet einen Thread, der zyklisch Modbus-Register abfragt und ModbusValueMaps aktualisiert pub fn start_modbus_polling_thread( - _modbus_config: &ModbusConfig, + modbus_config: &ModbusConfig, input_registers: &Option>>, holding_registers: &Option>>, coils: &Option>>, value_maps: Arc>, poll_interval: Duration, ) { + let host = modbus_config.host.clone(); + let port = modbus_config.port; + let input_registers = input_registers.clone(); let holding_registers = holding_registers.clone(); let coils = coils.clone(); thread::spawn(move || { + let addr: SocketAddr = format!("{}:{}", host, port).parse().unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); loop { - // Input Register - if let Some(ref vec) = input_registers { - for map in vec { - for (key, reg) in map { - let typ = reg.r#type.as_deref().unwrap_or(""); - let value = match typ { - "INT16" => { let raw: i16 = 0; raw as f64 }, - "UINT16" => { let raw: u16 = 0; raw as f64 }, - "UINT32" => { let raw1: u16 = 0; let raw2: u16 = 0; let raw32: u32 = ((raw1 as u32) << 16) | (raw2 as u32); raw32 as f64 }, - _ => 0.0, - }; - if let Ok(mut maps) = value_maps.lock() { - maps.modbus_input_register_values.insert(key.clone(), value); + // Verbindungsaufbau + let connect_result = rt.block_on(async { + tcp::connect_slave(addr, 1u8.into()).await + }); + match connect_result { + Ok(mut client) => { + // Werte abfragen + // Input Register + if let Some(ref vec) = input_registers { + for map in vec { + for (key, reg) in map { + let addr = reg.addr; + let typ = reg.r#type.as_deref().unwrap_or(""); + let factor = reg.factor.unwrap_or(1.0); + let value = rt.block_on(async { + match typ { + "INT16" | "UINT16" => client.read_input_registers(addr, 1).await.ok().map(|v| v[0] as f64 * factor), + "UINT32" => client.read_input_registers(addr, 2).await.ok().map(|v| ((v[0] as u32) << 16 | (v[1] as u32)) as f64 * factor), + _ => Some(0.0), + } + }).unwrap_or(0.0); + if let Ok(mut maps) = value_maps.lock() { + maps.modbus_input_register_values.insert(key.clone(), value); + } + } } } - } - } - // Holding Register - if let Some(ref vec) = holding_registers { - for map in vec { - for (key, reg) in map { - let typ = reg.r#type.as_deref().unwrap_or(""); - let value = match typ { - "INT16" => { let raw: i16 = 0; raw as f64 }, - "UINT16" => { let raw: u16 = 0; raw as f64 }, - "UINT32" => { let raw1: u16 = 0; let raw2: u16 = 0; let raw32: u32 = ((raw1 as u32) << 16) | (raw2 as u32); raw32 as f64 }, - _ => 0.0, - }; - if let Ok(mut maps) = value_maps.lock() { - maps.modbus_holding_register_values.insert(key.clone(), value); + // Holding Register + if let Some(ref vec) = holding_registers { + for map in vec { + for (key, reg) in map { + let addr = reg.addr; + let typ = reg.r#type.as_deref().unwrap_or(""); + let factor = reg.factor.unwrap_or(1.0); + let value = rt.block_on(async { + match typ { + "INT16" | "UINT16" => client.read_holding_registers(addr, 1).await.ok().map(|v| v[0] as f64 * factor), + "UINT32" => client.read_holding_registers(addr, 2).await.ok().map(|v| ((v[0] as u32) << 16 | (v[1] as u32)) as f64 * factor), + _ => Some(0.0), + } + }).unwrap_or(0.0); + if let Ok(mut maps) = value_maps.lock() { + maps.modbus_holding_register_values.insert(key.clone(), value); + } + } } } - } - } - // Coils - if let Some(ref vec) = coils { - for map in vec { - for (key, _reg) in map { - let value = 0.0; // Hier Coil-Wert abfragen - if let Ok(mut maps) = value_maps.lock() { - maps.modbus_coils_values.insert(key.clone(), value); + // Coils + if let Some(ref vec) = coils { + for map in vec { + for (key, reg) in map { + let addr = reg.addr; + let value = rt.block_on(async { + client.read_coils(addr, 1).await.ok().map(|v| if v[0] { 1.0 } else { 0.0 }) + }).unwrap_or(0.0); + if let Ok(mut maps) = value_maps.lock() { + maps.modbus_coils_values.insert(key.clone(), value); + } + } } } + }, + Err(_) => { + eprintln!("Modbus: Verbindung fehlgeschlagen, retry in {:?}", poll_interval); + thread::sleep(poll_interval); + continue; } } thread::sleep(poll_interval);