Modbus Werte werden nun ausgelesen

This commit is contained in:
Eric Neuber 2026-02-16 22:33:27 +01:00
parent c499f1b97c
commit 459b97d95c
4 changed files with 99 additions and 48 deletions

24
Cargo.lock generated
View File

@ -355,6 +355,12 @@ version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.11.0" version = "1.11.0"
@ -688,6 +694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
@ -1732,6 +1739,7 @@ dependencies = [
"serde_yaml", "serde_yaml",
"tera", "tera",
"tokio", "tokio",
"tokio-modbus",
"toml", "toml",
] ]
@ -1835,6 +1843,22 @@ dependencies = [
"syn", "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]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.17" version = "0.7.17"

View File

@ -16,3 +16,4 @@ tera = "1.19"
config = "0.14" config = "0.14"
toml = "0.8" toml = "0.8"
serde_derive = "1.0" serde_derive = "1.0"
tokio-modbus = "0.7"

View File

@ -1,14 +1,12 @@
default: default:
loglevel: DEBUG loglevel: DEBUG
darkmode: false darkmode: true
mqtt: mqtt:
broker: 192.168.178.2 broker: 192.168.178.2
button_circulation: zigbee2mqtt/WirelessButton
password: 97sm3pHNSMZ4M5qUj0x8
port: 1883 port: 1883
user: admin user: admin
password: 97sm3pHNSMZ4M5qUj0x8
button_circulation: zigbee2mqtt/WirelessButton
influxdb: influxdb:
bucket: Paradigma bucket: Paradigma
location: Radebeul location: Radebeul
@ -16,14 +14,12 @@ influxdb:
org: skaville org: skaville
token: i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ== token: i-sXFQbEkSC1XVzqFEaFwXwzasbsEIciVlK4SaAUOEvk0VjQPkD3fr8d7_3SPeyseTZkqj7ZMZU78b3n2F6_SQ==
url: 192.168.178.2:8086 url: 192.168.178.2:8086
modbus: modbus:
host: 192.168.178.10 host: 192.168.178.10
port: 502
max_coils_addr: 8 max_coils_addr: 8
max_holding_addr: 61 max_holding_addr: 61
max_input_addr: 45 max_input_addr: 45
port: 502
modbus_coils: modbus_coils:
- MgtSystem: {addr: 0, write: false, mqtt: false, influxdb: false, comment: Leitsystem aktiv} - MgtSystem: {addr: 0, write: false, mqtt: false, influxdb: false, comment: Leitsystem aktiv}
- HK1pres: {addr: 1, write: false, mqtt: false, influxdb: false, comment: HK1 vorhanden} - 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} - Zrelease: {addr: 6, write: true, mqtt: false, influxdb: false, comment: Zirkulation freigegeben}
- Zlock: {addr: 7, write: true, mqtt: false, influxdb: false, comment: Zirkulation gesperrt} - Zlock: {addr: 7, write: true, mqtt: false, influxdb: false, comment: Zirkulation gesperrt}
- SHKpres: {addr: 8, write: false, mqtt: false, influxdb: false, comment: Schwimmbadheizkrei vorhanden} - SHKpres: {addr: 8, write: false, mqtt: false, influxdb: false, comment: Schwimmbadheizkrei vorhanden}
modbus_input_register: modbus_input_register:
- TA: {addr: 0, type: INT16, factor: 0.1, mqtt: true, influxdb: true} - TA: {addr: 0, type: INT16, factor: 0.1, mqtt: true, influxdb: true}
- TV: {addr: 1, type: INT16, factor: 0.1, mqtt: false, 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} - TKW: {addr: 42, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
- VKW: {addr: 43, 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} - VSPm: {addr: 44, type: INT16, factor: 0.1, mqtt: false, influxdb: true}
modbus_holding_register: modbus_holding_register:
- nothing: {addr: 0, type: UINT16, factor: 1, mqtt: false, influxdb: false} - nothing: {addr: 0, type: UINT16, factor: 1, mqtt: false, influxdb: false}
- ErrLS: {addr: 1, type: UINT16, factor: 1, mqtt: false, influxdb: true} - ErrLS: {addr: 1, type: UINT16, factor: 1, mqtt: false, influxdb: true}

View File

@ -5,31 +5,50 @@ use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::time::Duration; 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 /// Startet einen Thread, der zyklisch Modbus-Register abfragt und ModbusValueMaps aktualisiert
pub fn start_modbus_polling_thread( pub fn start_modbus_polling_thread(
_modbus_config: &ModbusConfig, modbus_config: &ModbusConfig,
input_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>, input_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
holding_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>, holding_registers: &Option<Vec<HashMap<String, ModbusRegisterConfig>>>,
coils: &Option<Vec<HashMap<String, ModbusCoilsConfig>>>, coils: &Option<Vec<HashMap<String, ModbusCoilsConfig>>>,
value_maps: Arc<Mutex<ModbusValueMaps>>, value_maps: Arc<Mutex<ModbusValueMaps>>,
poll_interval: Duration, poll_interval: Duration,
) { ) {
let host = modbus_config.host.clone();
let port = modbus_config.port;
let input_registers = input_registers.clone(); let input_registers = input_registers.clone();
let holding_registers = holding_registers.clone(); let holding_registers = holding_registers.clone();
let coils = coils.clone(); let coils = coils.clone();
thread::spawn(move || { thread::spawn(move || {
let addr: SocketAddr = format!("{}:{}", host, port).parse().unwrap();
let rt = tokio::runtime::Runtime::new().unwrap();
loop { loop {
// 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 // Input Register
if let Some(ref vec) = input_registers { if let Some(ref vec) = input_registers {
for map in vec { for map in vec {
for (key, reg) in map { for (key, reg) in map {
let addr = reg.addr;
let typ = reg.r#type.as_deref().unwrap_or(""); let typ = reg.r#type.as_deref().unwrap_or("");
let value = match typ { let factor = reg.factor.unwrap_or(1.0);
"INT16" => { let raw: i16 = 0; raw as f64 }, let value = rt.block_on(async {
"UINT16" => { let raw: u16 = 0; raw as f64 }, match typ {
"UINT32" => { let raw1: u16 = 0; let raw2: u16 = 0; let raw32: u32 = ((raw1 as u32) << 16) | (raw2 as u32); raw32 as f64 }, "INT16" | "UINT16" => client.read_input_registers(addr, 1).await.ok().map(|v| v[0] as f64 * factor),
_ => 0.0, "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() { if let Ok(mut maps) = value_maps.lock() {
maps.modbus_input_register_values.insert(key.clone(), value); maps.modbus_input_register_values.insert(key.clone(), value);
} }
@ -40,13 +59,16 @@ pub fn start_modbus_polling_thread(
if let Some(ref vec) = holding_registers { if let Some(ref vec) = holding_registers {
for map in vec { for map in vec {
for (key, reg) in map { for (key, reg) in map {
let addr = reg.addr;
let typ = reg.r#type.as_deref().unwrap_or(""); let typ = reg.r#type.as_deref().unwrap_or("");
let value = match typ { let factor = reg.factor.unwrap_or(1.0);
"INT16" => { let raw: i16 = 0; raw as f64 }, let value = rt.block_on(async {
"UINT16" => { let raw: u16 = 0; raw as f64 }, match typ {
"UINT32" => { let raw1: u16 = 0; let raw2: u16 = 0; let raw32: u32 = ((raw1 as u32) << 16) | (raw2 as u32); raw32 as f64 }, "INT16" | "UINT16" => client.read_holding_registers(addr, 1).await.ok().map(|v| v[0] as f64 * factor),
_ => 0.0, "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() { if let Ok(mut maps) = value_maps.lock() {
maps.modbus_holding_register_values.insert(key.clone(), value); maps.modbus_holding_register_values.insert(key.clone(), value);
} }
@ -56,14 +78,24 @@ pub fn start_modbus_polling_thread(
// Coils // Coils
if let Some(ref vec) = coils { if let Some(ref vec) = coils {
for map in vec { for map in vec {
for (key, _reg) in map { for (key, reg) in map {
let value = 0.0; // Hier Coil-Wert abfragen 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() { if let Ok(mut maps) = value_maps.lock() {
maps.modbus_coils_values.insert(key.clone(), value); 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); thread::sleep(poll_interval);
} }
}); });