Schreibe MQTT.Set Werte, wenn das Leitsystem aktiv ist
Build Docker Image (Podman) / build (push) Failing after 15m52s

This commit is contained in:
eneuber committed 2026-03-13 22:56:06 +01:00
1 parent 497a0e48e3
commit 3ed80f4b68
6 files changed
+278 -39

No files matched your search

+107
View File
@@ -1,5 +1,6 @@
use crate::config::{ModbusValueMaps, ModbusConfig};
use crate::modbus_types::{ModbusInputRegisterConfig, ModbusHoldingRegisterConfig, ModbusCoilsConfig};
use crate::config::AppConfig;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
@@ -9,6 +10,112 @@ use tokio_modbus::prelude::*;
use tokio_modbus::client::tcp;
use std::net::SocketAddr;
pub fn write_value_by_name(config: &AppConfig, name: &str, payload: &str) -> Result<(), String> {
let addr: SocketAddr = format!("{}:{}", config.modbus.host, config.modbus.port)
.parse()
.map_err(|e| format!("Ungültige Modbus-Adresse: {}", e))?;
if let Some(ref coils) = config.modbus_coils {
for map in coils {
if let Some(coil) = map.get(name) {
if !coil.write.unwrap_or(false) {
return Err(format!("Schreiben für '{}' nicht erlaubt", name));
}
let bool_value = parse_bool_payload(payload)?;
let rt = tokio::runtime::Runtime::new()
.map_err(|e| format!("Tokio Runtime Fehler: {}", e))?;
rt.block_on(async {
let mut client = tcp::connect_slave(addr, 1u8.into())
.await
.map_err(|e| format!("Modbus Verbindung fehlgeschlagen: {}", e))?;
client
.write_single_coil(coil.addr, bool_value)
.await
.map_err(|e| format!("Coil schreiben fehlgeschlagen: {}", e))
})?;
return Ok(());
}
}
}
if let Some(ref holding_registers) = config.modbus_holding_register {
for map in holding_registers {
if let Some(reg) = map.get(name) {
if !reg.write.unwrap_or(false) {
return Err(format!("Schreiben für '{}' nicht erlaubt", name));
}
let numeric_value = payload
.trim()
.parse::<f64>()
.map_err(|e| format!("Ungültiger Zahlenwert '{}': {}", payload, e))?;
let factor = reg.factor.unwrap_or(1.0);
let raw = if factor == 0.0 {
numeric_value
} else {
numeric_value / factor
};
let rt = tokio::runtime::Runtime::new()
.map_err(|e| format!("Tokio Runtime Fehler: {}", e))?;
return rt.block_on(async {
let mut client = tcp::connect_slave(addr, 1u8.into())
.await
.map_err(|e| format!("Modbus Verbindung fehlgeschlagen: {}", e))?;
match reg.r#type.as_deref().unwrap_or("UINT16") {
"INT16" => {
let int_value = raw.round();
if int_value < i16::MIN as f64 || int_value > i16::MAX as f64 {
return Err(format!("Wert außerhalb INT16-Bereich für '{}': {}", name, numeric_value));
}
let register = int_value as i16 as u16;
client
.write_multiple_registers(reg.addr, &[register])
.await
.map_err(|e| format!("Holding Register schreiben fehlgeschlagen: {}", e))?;
}
"UINT32" => {
let int_value = raw.round();
if int_value < 0.0 || int_value > u32::MAX as f64 {
return Err(format!("Wert außerhalb UINT32-Bereich für '{}': {}", name, numeric_value));
}
let val = int_value as u32;
let high = ((val >> 16) & 0xFFFF) as u16;
let low = (val & 0xFFFF) as u16;
client
.write_multiple_registers(reg.addr, &[high, low])
.await
.map_err(|e| format!("Holding Register (UINT32) schreiben fehlgeschlagen: {}", e))?;
}
_ => {
let int_value = raw.round();
if int_value < 0.0 || int_value > u16::MAX as f64 {
return Err(format!("Wert außerhalb UINT16-Bereich für '{}': {}", name, numeric_value));
}
client
.write_multiple_registers(reg.addr, &[int_value as u16])
.await
.map_err(|e| format!("Holding Register schreiben fehlgeschlagen: {}", e))?;
}
}
Ok(())
});
}
}
}
Err(format!("Kein schreibbares Modbus-Mapping für '{}' gefunden", name))
}
fn parse_bool_payload(payload: &str) -> Result<bool, String> {
match payload.trim().to_ascii_lowercase().as_str() {
"1" | "true" | "on" => Ok(true),
"0" | "false" | "off" => Ok(false),
_ => Err(format!("Ungültiger bool-Wert '{}', erwartet 0/1 oder true/false", payload)),
}
}
/// Startet einen Thread, der zyklisch Modbus-Register abfragt und ModbusValueMaps aktualisiert
pub fn start_modbus_polling_thread(
modbus_config: &ModbusConfig,